@esposter/shared 4.1.2 → 4.2.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.
Files changed (3) hide show
  1. package/package.json +3 -3
  2. package/dist/index.d.ts +0 -2387
  3. package/dist/index.js +0 -1918
package/dist/index.js DELETED
@@ -1,1918 +0,0 @@
1
- import { z } from "zod";
2
- import { ResultAsync, fromThrowable } from "neverthrow";
3
- import { parse } from "node-html-parser";
4
- import mimeDatabase from "mime-db/db.json" with { type: "json" };
5
- import { defaultTreeAdapter, html as html$1, parseFragment } from "parse5";
6
- //#region src/models/error/ForbiddenError.ts
7
- var ForbiddenError = class extends Error {
8
- constructor(message) {
9
- super(message);
10
- this.name = "ForbiddenError";
11
- }
12
- };
13
- //#endregion
14
- //#region src/models/error/InvalidOperationError.ts
15
- var InvalidOperationError = class extends Error {
16
- constructor(operation, name, message) {
17
- super(`Invalid operation: ${operation}, name: ${name}, ${message}`);
18
- this.name = "InvalidOperationError";
19
- }
20
- };
21
- //#endregion
22
- //#region src/models/error/NotFoundError.ts
23
- var NotFoundError = class extends Error {
24
- constructor(name, id) {
25
- super(`${name} is not found for id: ${id}`);
26
- this.name = "NotFoundError";
27
- }
28
- };
29
- //#endregion
30
- //#region src/models/error/NotInitializedError.ts
31
- var NotInitializedError = class extends Error {
32
- constructor(name) {
33
- super(`${name} is not initialized`);
34
- this.name = "NotInitializedError";
35
- }
36
- };
37
- //#endregion
38
- //#region src/models/error/WordFilteredError.ts
39
- var WordFilteredError = class extends Error {
40
- constructor(message) {
41
- super(message);
42
- this.name = "WordFilteredError";
43
- }
44
- };
45
- //#endregion
46
- //#region src/models/shared/Operation.ts
47
- let Operation = /* @__PURE__ */ function(Operation) {
48
- Operation["Create"] = "Create";
49
- Operation["Delete"] = "Delete";
50
- Operation["Push"] = "Push";
51
- Operation["Read"] = "Read";
52
- Operation["Unshift"] = "Unshift";
53
- Operation["Update"] = "Update";
54
- return Operation;
55
- }({});
56
- //#endregion
57
- //#region src/models/eventEmitter/TypedEventEmitter.ts
58
- var TypedEventEmitter = class {
59
- #entriesMap = /* @__PURE__ */ new Map();
60
- emit(event, ...args) {
61
- const entries = this.#entriesMap.get(event) ?? [];
62
- if (entries.length === 0) return false;
63
- this.#setEntries(event, entries.filter((entry) => !entry.isOnce));
64
- for (const { listener } of entries) listener(...args);
65
- return true;
66
- }
67
- off(event, listener) {
68
- this.#setEntries(event, (this.#entriesMap.get(event) ?? []).filter((entry) => entry.listener !== listener));
69
- }
70
- on(event, listener) {
71
- this.#addEntry(event, listener, false);
72
- }
73
- once(event, listener) {
74
- this.#addEntry(event, listener, true);
75
- }
76
- removeAllListeners(event) {
77
- if (event === void 0) this.#entriesMap.clear();
78
- else this.#entriesMap.delete(event);
79
- }
80
- #addEntry(event, listener, isOnce) {
81
- if (typeof listener !== "function") throw new InvalidOperationError("Create", String(event), "The listener must be a function");
82
- this.#setEntries(event, [...this.#entriesMap.get(event) ?? [], {
83
- isOnce,
84
- listener
85
- }]);
86
- }
87
- #setEntries(event, entries) {
88
- if (entries.length === 0) this.#entriesMap.delete(event);
89
- else this.#entriesMap.set(event, entries);
90
- }
91
- };
92
- //#endregion
93
- //#region src/models/message/MentionType.ts
94
- let MentionType = /* @__PURE__ */ function(MentionType) {
95
- MentionType["Role"] = "role";
96
- MentionType["User"] = "user";
97
- return MentionType;
98
- }({});
99
- //#endregion
100
- //#region src/models/object/ObjectMethod.ts
101
- let ObjectMethod = /* @__PURE__ */ function(ObjectMethod) {
102
- ObjectMethod["ToString"] = "toString";
103
- ObjectMethod["ValueOf"] = "valueOf";
104
- return ObjectMethod;
105
- }({});
106
- //#endregion
107
- //#region src/services/app/constants.ts
108
- const MAX_READ_LIMIT = 1e3;
109
- const SITE_NAME = "Esposter";
110
- const KIBIBYTE = 1024;
111
- const GIBIBYTE = KIBIBYTE ** 2 * KIBIBYTE;
112
- //#endregion
113
- //#region src/models/router/RoutePath.ts
114
- const RoutePath = {
115
- About: "/about",
116
- Achievements: "/achievements",
117
- Anime: "/anime",
118
- Calls: (id) => `/calls/${id}`,
119
- CallsIndex: "/calls",
120
- Clicker: "/clicker",
121
- Docs: "/docs",
122
- Dungeons: "/dungeons",
123
- FluidSimulator: "/fluid-simulator",
124
- Genshin: "/genshin",
125
- Github: `https://github.com/${SITE_NAME}/${SITE_NAME}`,
126
- Index: "/",
127
- Login: "/login",
128
- Messages: (id) => `/messages/${id}`,
129
- MessagesDraftsAndSent: "/messages/draftsandsent",
130
- MessagesFriends: "/messages/friends",
131
- MessagesIndex: "/messages",
132
- MessagesInvite: (code) => `/messages/invite/${code}`,
133
- MessagesMessage: (id, rowKey) => `/messages/${id}/${rowKey}`,
134
- MessagesThread: (id, rowKey) => `/messages/${id}/thread/${rowKey}`,
135
- Post: (id) => `/post/${id}`,
136
- PostCreate: "/post/create",
137
- PostUpdate: (id) => `/post/update/${id}`,
138
- PrivacyPolicy: "/privacy-policy",
139
- Resource: (id) => `/resource-explorer/${id}`,
140
- ResourceExplorer: "/resource-explorer",
141
- ResourceExplorerAll: "/resource-explorer/all",
142
- ResourceExplorerCreate: "/resource-explorer/create",
143
- ResourceExplorerCreateType: (type) => `/resource-explorer/create/${type}`,
144
- ResourceExplorerFavorites: "/resource-explorer/favorites",
145
- ResourceExplorerRecents: "/resource-explorer/recents",
146
- ResourceExplorerRecycleBin: "/resource-explorer/recycle-bin",
147
- ResourceExplorerTags: "/resource-explorer/tags",
148
- ResourceItems: (id) => `/resource-explorer/${id}/items`,
149
- User: (id) => `/user/${id}`,
150
- UserSettings: "/user/settings",
151
- View: (type, id) => `/view/${type}/${id}`
152
- };
153
- //#endregion
154
- //#region src/models/shared/ItemEntityType.ts
155
- const createItemEntityTypeSchema = (schema) => z.object({ type: schema });
156
- //#endregion
157
- //#region src/models/shared/ItemMetadata.ts
158
- var ItemMetadata = class {
159
- createdAt = /* @__PURE__ */ new Date();
160
- deletedAt = null;
161
- updatedAt = /* @__PURE__ */ new Date();
162
- };
163
- //#endregion
164
- //#region src/util/reactivity/getRawData.ts
165
- const getRawData = (data) => {
166
- const raw = data && data.__v_raw;
167
- return raw ? getRawData(raw) : data;
168
- };
169
- //#endregion
170
- //#region src/util/reactivity/toRawDeep.ts
171
- const toRawDeep = (data) => {
172
- const rawData = getRawData(data);
173
- for (const key in rawData) if (Object.hasOwn(rawData, key)) {
174
- const value = rawData[key];
175
- if (value !== null && typeof value === "object") rawData[key] = toRawDeep(value);
176
- }
177
- return rawData;
178
- };
179
- //#endregion
180
- //#region src/models/shared/Serializable.ts
181
- var Serializable = class {
182
- toJSON() {
183
- return structuredClone(toRawDeep(this));
184
- }
185
- };
186
- //#endregion
187
- //#region src/services/error/toAppError.ts
188
- const toAppError = (error) => {
189
- if (error instanceof Error) return error;
190
- else if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") return new Error(error.message, { cause: error });
191
- else return new Error(String(error), { cause: error });
192
- };
193
- //#endregion
194
- //#region src/services/error/getResult.ts
195
- const getResult = (callback) => fromThrowable(callback, toAppError)();
196
- //#endregion
197
- //#region src/services/error/getResultAsync.ts
198
- const getResultAsync = (callback) => ResultAsync.fromThrowable(callback, toAppError)();
199
- //#endregion
200
- //#region src/services/error/reportFinalizerError.ts
201
- const reportFinalizerError = (callbackResult, finalizerError) => {
202
- callbackResult.match(() => {
203
- throw finalizerError;
204
- }, () => {
205
- console.error(finalizerError);
206
- });
207
- };
208
- //#endregion
209
- //#region src/util/function/noop.ts
210
- const noop = () => {};
211
- //#endregion
212
- //#region src/services/error/withFinalizer.ts
213
- const withFinalizer = (callback, finalizer) => {
214
- const callbackResult = getResult(callback);
215
- if (finalizer) getResult(finalizer).match(noop, (error) => {
216
- reportFinalizerError(callbackResult, error);
217
- });
218
- return callbackResult.match((value) => value, (error) => {
219
- throw error;
220
- });
221
- };
222
- //#endregion
223
- //#region src/services/error/withFinalizerAsync.ts
224
- const withFinalizerAsync = async (callback, finalizer) => {
225
- const callbackResult = await getResultAsync(async () => callback());
226
- if (finalizer) await getResultAsync(async () => finalizer()).match(noop, (error) => {
227
- reportFinalizerError(callbackResult, error);
228
- });
229
- return callbackResult.match((value) => value, (error) => {
230
- throw error;
231
- });
232
- };
233
- //#endregion
234
- //#region src/services/indexedDb/getRequestError.ts
235
- const getRequestError = (request) => request.error ?? new DOMException("The request failed without an error", "UnknownError");
236
- //#endregion
237
- //#region src/services/indexedDb/getTransactionDone.ts
238
- const getTransactionDone = (transaction) => new Promise((resolve, reject) => {
239
- transaction.addEventListener("complete", () => {
240
- resolve();
241
- });
242
- transaction.addEventListener("abort", () => {
243
- reject(transaction.error ?? new DOMException("The transaction was aborted", "AbortError"));
244
- });
245
- });
246
- //#endregion
247
- //#region src/services/indexedDb/requestToPromise.ts
248
- const requestToPromise = (request) => new Promise((resolve, reject) => {
249
- request.addEventListener("success", () => {
250
- resolve(request.result);
251
- });
252
- request.addEventListener("error", () => {
253
- reject(getRequestError(request));
254
- });
255
- });
256
- //#endregion
257
- //#region src/services/indexedDb/wrapIndex.ts
258
- const wrapIndex = (index) => ({
259
- getAll: (query, count) => requestToPromise(index.getAll(query, count)),
260
- getAllKeys: (query, count) => requestToPromise(index.getAllKeys(query, count))
261
- });
262
- //#endregion
263
- //#region src/services/indexedDb/wrapObjectStore.ts
264
- const wrapObjectStore = (objectStore) => {
265
- const reader = {
266
- get: (key) => requestToPromise(objectStore.get(key)),
267
- getAll: (query, count) => requestToPromise(objectStore.getAll(query, count)),
268
- getAllKeys: (query, count) => requestToPromise(objectStore.getAllKeys(query, count)),
269
- index: (name) => wrapIndex(objectStore.index(name))
270
- };
271
- const writer = {
272
- delete: (query) => requestToPromise(objectStore.delete(query)),
273
- put: (value, key) => requestToPromise(objectStore.put(value, key))
274
- };
275
- const creator = { createIndex: (name, keyPath, options) => {
276
- objectStore.createIndex(name, keyPath, options);
277
- } };
278
- return {
279
- ...reader,
280
- ...writer,
281
- ...creator
282
- };
283
- };
284
- //#endregion
285
- //#region src/services/indexedDb/getTransactionObjectStore.ts
286
- const getTransactionObjectStore = (transaction) => (name) => wrapObjectStore(transaction.objectStore(name));
287
- //#endregion
288
- //#region src/services/indexedDb/wrapTransaction.ts
289
- const wrapTransaction = (transaction) => ({
290
- done: getTransactionDone(transaction),
291
- objectStore: getTransactionObjectStore(transaction)
292
- });
293
- //#endregion
294
- //#region src/services/indexedDb/wrapDatabase.ts
295
- const wrapDatabase = (database) => {
296
- const getReadonlyObjectStore = (storeName) => wrapObjectStore(database.transaction(storeName, "readonly").objectStore(storeName));
297
- const getReadwriteObjectStore = (storeName) => wrapObjectStore(database.transaction(storeName, "readwrite").objectStore(storeName));
298
- const transaction = (storeNames, mode, options) => {
299
- const names = typeof storeNames === "string" ? storeNames : [...storeNames];
300
- return wrapTransaction(database.transaction(names, mode, options));
301
- };
302
- return {
303
- close: () => {
304
- database.close();
305
- },
306
- delete: (storeName, query) => getReadwriteObjectStore(storeName).delete(query),
307
- get: (storeName, key) => getReadonlyObjectStore(storeName).get(key),
308
- getAll: (storeName, query, count) => getReadonlyObjectStore(storeName).getAll(query, count),
309
- getAllKeys: (storeName, query, count) => getReadonlyObjectStore(storeName).getAllKeys(query, count),
310
- name: database.name,
311
- put: (storeName, value, key) => getReadwriteObjectStore(storeName).put(value, key),
312
- transaction
313
- };
314
- };
315
- //#endregion
316
- //#region src/services/indexedDb/wrapUpgradeDatabase.ts
317
- const wrapUpgradeDatabase = (database) => ({
318
- ...wrapDatabase(database),
319
- createObjectStore: (name, options) => wrapObjectStore(database.createObjectStore(name, options))
320
- });
321
- //#endregion
322
- //#region src/services/indexedDb/wrapUpgradeTransaction.ts
323
- const wrapUpgradeTransaction = (transaction) => {
324
- const done = getTransactionDone(transaction);
325
- getResultAsync(() => done).match(noop, console.error);
326
- return {
327
- get done() {
328
- return done;
329
- },
330
- objectStore: getTransactionObjectStore(transaction)
331
- };
332
- };
333
- //#endregion
334
- //#region src/services/indexedDb/openDatabase.ts
335
- const openDatabase = (name, version, options = {}) => new Promise((resolve, reject) => {
336
- const request = indexedDB.open(name, version);
337
- request.addEventListener("blocked", (event) => {
338
- options.blocked?.(event.oldVersion, event.newVersion);
339
- });
340
- request.addEventListener("upgradeneeded", (event) => {
341
- const { transaction } = request;
342
- if (!transaction) return;
343
- getResult(() => options.upgrade?.(wrapUpgradeDatabase(request.result), event.oldVersion, event.newVersion, wrapUpgradeTransaction(transaction))).match(noop, (error) => {
344
- console.error(error);
345
- transaction.abort();
346
- });
347
- });
348
- request.addEventListener("success", () => {
349
- const database = request.result;
350
- database.addEventListener("close", () => {
351
- options.terminated?.();
352
- });
353
- database.addEventListener("versionchange", (event) => {
354
- options.blocking?.(event.oldVersion, event.newVersion);
355
- });
356
- resolve(wrapDatabase(database));
357
- });
358
- request.addEventListener("error", () => {
359
- reject(getRequestError(request));
360
- });
361
- });
362
- //#endregion
363
- //#region src/services/message/constants.ts
364
- const MENTION_ID_ATTRIBUTE = "data-id";
365
- const MENTION_ITEM_TYPE_ATTRIBUTE = "data-mention-type";
366
- const MENTION_LABEL_ATTRIBUTE = "data-label";
367
- const MENTION_TYPE_ATTRIBUTE = "data-type";
368
- const MENTION_TYPE = "mention";
369
- const MENTION_SELECTOR = `span[${MENTION_TYPE_ATTRIBUTE}='${MENTION_TYPE}']`;
370
- const MENTION_HERE_ID = "@here";
371
- const MENTION_EVERYONE_ID = "@everyone";
372
- const CUSTOM_EMOJI_ID_ATTRIBUTE = "data-custom-emoji-id";
373
- const CUSTOM_EMOJI_NAME_ATTRIBUTE = "data-custom-emoji-name";
374
- const SPOILER_ATTRIBUTE = "data-spoiler";
375
- const SPOILER_SELECTOR = `span[${SPOILER_ATTRIBUTE}]`;
376
- //#endregion
377
- //#region src/services/message/getMentions.ts
378
- const getMentions = (message) => parse(message).querySelectorAll(MENTION_SELECTOR);
379
- //#endregion
380
- //#region src/services/mime/constants.ts
381
- const MEDIA_TYPE_REGEX = /^\s*(?<mediaType>[^;\s]*)(?:;|\s|$)/u;
382
- const PATH_SEPARATOR_REGEX = /[/\\]/u;
383
- const TEXT_MEDIA_TYPE_REGEX = /^text\//iu;
384
- const CHARSET_PARAMETER_REGEX = /;\s*charset=/iu;
385
- const DEFAULT_TEXT_CHARSET = "UTF-8";
386
- const FacetScoreMap = /* @__PURE__ */ new Map([
387
- ["prs.", 100],
388
- ["vnd.", 400],
389
- ["x-", 200],
390
- ["x.", 300]
391
- ]);
392
- const DEFAULT_FACET_SCORE = 900;
393
- const SourceScoreMap = /* @__PURE__ */ new Map([
394
- ["apache", 20],
395
- ["iana", 40],
396
- ["nginx", 10]
397
- ]);
398
- const DEFAULT_SOURCE_SCORE = 30;
399
- const TypeScoreMap = /* @__PURE__ */ new Map([
400
- ["application", 1],
401
- ["audio", 2],
402
- ["font", 2],
403
- ["video", 3]
404
- ]);
405
- const DEFAULT_TYPE_SCORE = 0;
406
- //#endregion
407
- //#region src/services/mime/getMediaType.ts
408
- const getMediaType = (value) => MEDIA_TYPE_REGEX.exec(value)?.groups?.mediaType ?? "";
409
- //#endregion
410
- //#region src/services/mime/getMimeTypeEntryMap.ts
411
- let mimeTypeEntryMap;
412
- const getMimeTypeEntryMap = () => {
413
- mimeTypeEntryMap ??= new Map(Object.entries(mimeDatabase));
414
- return mimeTypeEntryMap;
415
- };
416
- //#endregion
417
- //#region src/services/mime/charset.ts
418
- const charset = (type) => {
419
- const mediaType = getMediaType(type);
420
- const dataCharset = getMimeTypeEntryMap().get(mediaType.toLowerCase())?.charset;
421
- if (dataCharset) return dataCharset;
422
- return TEXT_MEDIA_TYPE_REGEX.test(mediaType) ? DEFAULT_TEXT_CHARSET : false;
423
- };
424
- //#endregion
425
- //#region src/services/mime/getMimeScore.ts
426
- const getMimeScore = (mimeType, source = "") => {
427
- if (mimeType === "application/octet-stream") return 0;
428
- const [type = "", subtype = ""] = mimeType.split("/");
429
- const facet = subtype.replace(/(?<prefix>\.|x-).*/u, "$<prefix>");
430
- const facetScore = FacetScoreMap.get(facet) ?? 900;
431
- const sourceScore = SourceScoreMap.get(source) ?? 30;
432
- const typeScore = TypeScoreMap.get(type) ?? 0;
433
- const lengthScore = 1 - mimeType.length / 100;
434
- return facetScore + sourceScore + typeScore + lengthScore;
435
- };
436
- //#endregion
437
- //#region src/services/mime/getExtensionMimeTypeMap.ts
438
- let extensionMimeTypeMap;
439
- const getPreferredMimeType = (currentMimeType, candidateMimeType) => {
440
- if (currentMimeType === void 0) return candidateMimeType;
441
- const entryMap = getMimeTypeEntryMap();
442
- return getMimeScore(currentMimeType, entryMap.get(currentMimeType)?.source) > getMimeScore(candidateMimeType, entryMap.get(candidateMimeType)?.source) ? currentMimeType : candidateMimeType;
443
- };
444
- const getExtensionMimeTypeMap = () => {
445
- if (!extensionMimeTypeMap) {
446
- const map = /* @__PURE__ */ new Map();
447
- for (const [mimeType, { extensions = [] }] of getMimeTypeEntryMap()) for (const extension of extensions) map.set(extension, getPreferredMimeType(map.get(extension), mimeType));
448
- extensionMimeTypeMap = map;
449
- }
450
- return extensionMimeTypeMap;
451
- };
452
- //#endregion
453
- //#region src/services/mime/lookup.ts
454
- const getExtension = (path) => {
455
- const name = path.split(PATH_SEPARATOR_REGEX).at(-1) ?? "";
456
- const dotIndex = name.lastIndexOf(".");
457
- if (path === name) return name.slice(dotIndex + 1);
458
- return dotIndex > 0 ? name.slice(dotIndex + 1) : "";
459
- };
460
- const lookup = (path) => {
461
- const extension = getExtension(path).toLowerCase();
462
- if (!extension) return false;
463
- return getExtensionMimeTypeMap().get(extension) ?? false;
464
- };
465
- //#endregion
466
- //#region src/services/mime/contentType.ts
467
- const contentType = (value) => {
468
- const mediaType = value.includes("/") ? value : lookup(value);
469
- if (!mediaType) return false;
470
- if (CHARSET_PARAMETER_REGEX.test(mediaType)) return mediaType;
471
- const mediaCharset = charset(mediaType);
472
- return mediaCharset ? `${mediaType}; charset=${mediaCharset.toLowerCase()}` : mediaType;
473
- };
474
- //#endregion
475
- //#region src/services/mime/extension.ts
476
- const extension = (type) => getMimeTypeEntryMap().get(getMediaType(type).toLowerCase())?.extensions?.[0] ?? false;
477
- //#endregion
478
- //#region src/services/prettier/css.ts
479
- const css = String.raw;
480
- //#endregion
481
- //#region src/services/prettier/html.ts
482
- const html = String.raw;
483
- //#endregion
484
- //#region src/services/profanity/englishProfaneWords.ts
485
- const englishProfaneWords = [
486
- "4r5e",
487
- "5h1t",
488
- "5hit",
489
- "a55",
490
- "anal",
491
- "anus",
492
- "ar5e",
493
- "arrse",
494
- "arse",
495
- "arses",
496
- "ass",
497
- "ass-fucker",
498
- "asses",
499
- "assfucker",
500
- "assfukka",
501
- "asshole",
502
- "assholes",
503
- "asswhole",
504
- "a_s_s",
505
- "a$$",
506
- "as$",
507
- "a$s",
508
- "b!tch",
509
- "b00bs",
510
- "b17ch",
511
- "b1tch",
512
- "ballbag",
513
- "balls",
514
- "ballsack",
515
- "bastard",
516
- "beastial",
517
- "beastiality",
518
- "bellend",
519
- "bestial",
520
- "bestiality",
521
- "bi+ch",
522
- "biatch",
523
- "bitch",
524
- "bitchboy",
525
- "bitcher",
526
- "bitchers",
527
- "bitches",
528
- "bitchin",
529
- "bitching",
530
- "bloody",
531
- "blow job",
532
- "blowjob",
533
- "blowjobs",
534
- "boiolas",
535
- "bollock",
536
- "bollok",
537
- "boner",
538
- "boob",
539
- "boobs",
540
- "booobs",
541
- "boooobs",
542
- "booooobs",
543
- "booooooobs",
544
- "breasts",
545
- "buceta",
546
- "bugger",
547
- "bullshit",
548
- "bum",
549
- "butt",
550
- "butts",
551
- "butthole",
552
- "buttmuch",
553
- "buttplug",
554
- "c0ck",
555
- "c0cksucker",
556
- "carpet muncher",
557
- "cawk",
558
- "chink",
559
- "cipa",
560
- "cl1t",
561
- "clit",
562
- "clitoris",
563
- "clits",
564
- "cnut",
565
- "cock",
566
- "cock-sucker",
567
- "cockface",
568
- "cockhead",
569
- "cockmunch",
570
- "cockmuncher",
571
- "cocks",
572
- "cocksuck",
573
- "cocksucked",
574
- "cocksucker",
575
- "cocksucking",
576
- "cocksucks",
577
- "cocksuka",
578
- "cocksukka",
579
- "cok",
580
- "cokmuncher",
581
- "coksucka",
582
- "coon",
583
- "cox",
584
- "crap",
585
- "cum",
586
- "cummer",
587
- "cumming",
588
- "cums",
589
- "cumshot",
590
- "cunilingus",
591
- "cunillingus",
592
- "cunnilingus",
593
- "cunt",
594
- "cuntlick",
595
- "cuntlicker",
596
- "cuntlicking",
597
- "cunts",
598
- "cyalis",
599
- "cyberfuc",
600
- "cyberfuck",
601
- "cyberfucked",
602
- "cyberfucker",
603
- "cyberfuckers",
604
- "cyberfucking",
605
- "d1ck",
606
- "damn",
607
- "dick",
608
- "dickhead",
609
- "dildo",
610
- "dildos",
611
- "dink",
612
- "dinks",
613
- "dirsa",
614
- "dlck",
615
- "dog-fucker",
616
- "doggin",
617
- "dogging",
618
- "donkeyribber",
619
- "doosh",
620
- "duche",
621
- "dyke",
622
- "ejaculate",
623
- "ejaculated",
624
- "ejaculates",
625
- "ejaculating",
626
- "ejaculatings",
627
- "ejaculation",
628
- "ejakulate",
629
- "f u c k",
630
- "f u c k e r",
631
- "f4nny",
632
- "fag",
633
- "fagging",
634
- "faggitt",
635
- "faggot",
636
- "faggs",
637
- "fagot",
638
- "fagots",
639
- "fags",
640
- "fanny",
641
- "fannyflaps",
642
- "fannyfucker",
643
- "fanyy",
644
- "fatass",
645
- "fcuk",
646
- "fcuker",
647
- "fcuking",
648
- "feck",
649
- "fecker",
650
- "felching",
651
- "fellate",
652
- "fellatio",
653
- "fingerfuck",
654
- "fingerfucked",
655
- "fingerfucker",
656
- "fingerfuckers",
657
- "fingerfucking",
658
- "fingerfucks",
659
- "fistfuck",
660
- "fistfucked",
661
- "fistfucker",
662
- "fistfuckers",
663
- "fistfucking",
664
- "fistfuckings",
665
- "fistfucks",
666
- "flange",
667
- "fook",
668
- "fooker",
669
- "fuck",
670
- "fucka",
671
- "fucked",
672
- "fucker",
673
- "fuckers",
674
- "fuckhead",
675
- "fuckheads",
676
- "fuckin",
677
- "fucking",
678
- "fuckings",
679
- "fuckingshitmotherfucker",
680
- "fuckme",
681
- "fucks",
682
- "fuckwhit",
683
- "fuckwit",
684
- "fudge packer",
685
- "fudgepacker",
686
- "fuk",
687
- "fuker",
688
- "fukker",
689
- "fukkin",
690
- "fuks",
691
- "fukwhit",
692
- "fukwit",
693
- "fux",
694
- "fux0r",
695
- "f_u_c_k",
696
- "gangbang",
697
- "gangbanged",
698
- "gangbangs",
699
- "gaylord",
700
- "gaysex",
701
- "goatse",
702
- "god-dam",
703
- "god-damned",
704
- "goddamn",
705
- "goddamned",
706
- "hardcoresex",
707
- "headass",
708
- "hoar",
709
- "hoare",
710
- "hoer",
711
- "hoes",
712
- "homo",
713
- "hore",
714
- "horniest",
715
- "horny",
716
- "hotsex",
717
- "jack-off",
718
- "jackoff",
719
- "jap",
720
- "jerk-off",
721
- "jism",
722
- "jiz",
723
- "jizm",
724
- "jizz",
725
- "kawk",
726
- "knobead",
727
- "knobed",
728
- "knobend",
729
- "knobhead",
730
- "knobjocky",
731
- "knobjokey",
732
- "kock",
733
- "kondum",
734
- "kondums",
735
- "kum",
736
- "kummer",
737
- "kumming",
738
- "kums",
739
- "kunilingus",
740
- "l3i+ch",
741
- "l3itch",
742
- "labia",
743
- "lust",
744
- "lusting",
745
- "m0f0",
746
- "m0fo",
747
- "m45terbate",
748
- "ma5terb8",
749
- "ma5terbate",
750
- "masochist",
751
- "master-bate",
752
- "masterb8",
753
- "masterbat*",
754
- "masterbat3",
755
- "masterbate",
756
- "masterbation",
757
- "masterbations",
758
- "masturbate",
759
- "mo-fo",
760
- "mof0",
761
- "mofo",
762
- "mothafuck",
763
- "mothafucka",
764
- "mothafuckas",
765
- "mothafuckaz",
766
- "mothafucked",
767
- "mothafucker",
768
- "mothafuckers",
769
- "mothafuckin",
770
- "mothafucking",
771
- "mothafuckings",
772
- "mothafucks",
773
- "motherfuck",
774
- "motherfucked",
775
- "motherfucker",
776
- "motherfuckers",
777
- "motherfuckin",
778
- "motherfucking",
779
- "motherfuckings",
780
- "motherfuckka",
781
- "motherfucks",
782
- "muff",
783
- "muthafecker",
784
- "muthafuckker",
785
- "mutherfucker",
786
- "n1gga",
787
- "n1gger",
788
- "nazi",
789
- "nigg3r",
790
- "nigg4h",
791
- "nigga",
792
- "niggah",
793
- "niggas",
794
- "niggaz",
795
- "nigger",
796
- "niggers",
797
- "nob",
798
- "nob jokey",
799
- "nobhead",
800
- "nobjocky",
801
- "nobjokey",
802
- "numbnuts",
803
- "nutsack",
804
- "orgasim",
805
- "orgasims",
806
- "orgasm",
807
- "orgasms",
808
- "p0rn",
809
- "pawn",
810
- "pecker",
811
- "penis",
812
- "penisfucker",
813
- "phonesex",
814
- "phuck",
815
- "phuk",
816
- "phuked",
817
- "phuking",
818
- "phukked",
819
- "phukking",
820
- "phuks",
821
- "phuq",
822
- "pigfucker",
823
- "pimpis",
824
- "piss",
825
- "pissed",
826
- "pisser",
827
- "pissers",
828
- "pisses",
829
- "pissflaps",
830
- "pissin",
831
- "pissing",
832
- "pissoff",
833
- "poop",
834
- "porn",
835
- "porno",
836
- "pornography",
837
- "pornos",
838
- "prick",
839
- "pricks",
840
- "pron",
841
- "pube",
842
- "pusse",
843
- "pussi",
844
- "pussies",
845
- "pussy",
846
- "pussys",
847
- "rectum",
848
- "retard",
849
- "rimjaw",
850
- "rimming",
851
- "s hit",
852
- "s.o.b.",
853
- "sadist",
854
- "schlong",
855
- "screwing",
856
- "scroat",
857
- "scrote",
858
- "scrotum",
859
- "semen",
860
- "sex",
861
- "sh!+",
862
- "sh!t",
863
- "sh1t",
864
- "shag",
865
- "shagger",
866
- "shaggin",
867
- "shagging",
868
- "shemale",
869
- "shi+",
870
- "shit",
871
- "shitdick",
872
- "shite",
873
- "shited",
874
- "shitey",
875
- "shitfuck",
876
- "shitfull",
877
- "shithead",
878
- "shiting",
879
- "shitings",
880
- "shits",
881
- "shitted",
882
- "shitter",
883
- "shitters",
884
- "shitting",
885
- "shittings",
886
- "shitty",
887
- "skank",
888
- "slut",
889
- "sluts",
890
- "smegma",
891
- "smut",
892
- "snatch",
893
- "son-of-a-bitch",
894
- "spac",
895
- "spunk",
896
- "s_h_i_t",
897
- "t1tt1e5",
898
- "t1tties",
899
- "teets",
900
- "teez",
901
- "testical",
902
- "testicle",
903
- "tit",
904
- "titfuck",
905
- "tits",
906
- "titt",
907
- "tittie5",
908
- "tittiefucker",
909
- "titties",
910
- "tittyfuck",
911
- "tittywank",
912
- "titwank",
913
- "tosser",
914
- "turd",
915
- "tw4t",
916
- "twat",
917
- "twathead",
918
- "twatty",
919
- "twunt",
920
- "twunter",
921
- "v14gra",
922
- "v1gra",
923
- "vagina",
924
- "viagra",
925
- "vulva",
926
- "w00se",
927
- "wang",
928
- "wank",
929
- "wanker",
930
- "wanky",
931
- "whoar",
932
- "whore",
933
- "willies",
934
- "willy"
935
- ];
936
- //#endregion
937
- //#region src/services/profanity/checkContainsProfanity.ts
938
- const WORD_CHARACTER_CLASS = String.raw`\p{L}\p{N}\p{M}`;
939
- const PROFANE_WORD_ALTERNATION = englishProfaneWords.map((word) => word.replaceAll(/[.*+?^${}()|[\]\\]/gu, String.raw`\$&`)).join("|");
940
- const WHOLE_WORD_PROFANITY_REGEX = new RegExp(`(?<![${WORD_CHARACTER_CLASS}])(?:${PROFANE_WORD_ALTERNATION})(?![${WORD_CHARACTER_CLASS}])`, "iu");
941
- const SUBSTRING_PROFANITY_REGEX = new RegExp(PROFANE_WORD_ALTERNATION, "iu");
942
- const checkContainsProfanity = (text, { isWholeWord = true } = {}) => {
943
- if (typeof text !== "string") return false;
944
- return (isWholeWord ? WHOLE_WORD_PROFANITY_REGEX : SUBSTRING_PROFANITY_REGEX).test(text);
945
- };
946
- //#endregion
947
- //#region src/services/sanitizeHtml/checkIsWhitespaceCharacter.ts
948
- const checkIsWhitespaceCharacter = (character) => character.trim() === "";
949
- //#endregion
950
- //#region src/services/sanitizeHtml/checkIsUnsafeUrlCharacter.ts
951
- const FIRST_PRINTABLE_CODE_POINT = 32;
952
- const DELETE_CODE_POINT = 127;
953
- const LAST_C1_CONTROL_CODE_POINT = 159;
954
- const GRAVE_ACCENT = "`";
955
- const checkIsUnsafeUrlCharacter = (character) => {
956
- const codePoint = character.codePointAt(0) ?? 0;
957
- return checkIsWhitespaceCharacter(character) || codePoint < FIRST_PRINTABLE_CODE_POINT || codePoint >= DELETE_CODE_POINT && codePoint <= LAST_C1_CONTROL_CODE_POINT || character === GRAVE_ACCENT;
958
- };
959
- //#endregion
960
- //#region src/util/array/takeOne.ts
961
- const takeOne = (values, index = 0) => {
962
- return values[index];
963
- };
964
- //#endregion
965
- //#region src/services/sanitizeHtml/checkIsAllowedUrl.ts
966
- const PATH_DELIMITER_REGEX = /[/?#]/u;
967
- const NON_SCHEME_CHARACTERS_REGEX = /[^a-z\d+.-]/giu;
968
- const SCHEME_SEPARATOR = ":";
969
- const checkIsAllowedUrl = (url, allowedSchemes) => {
970
- const normalizedUrl = url.split("").filter((character) => !checkIsUnsafeUrlCharacter(character)).join("");
971
- const beforePath = takeOne(normalizedUrl.split(PATH_DELIMITER_REGEX), 0);
972
- const separatorIndex = beforePath.indexOf(SCHEME_SEPARATOR);
973
- if (separatorIndex === -1) return true;
974
- const scheme = beforePath.slice(0, separatorIndex).replace(NON_SCHEME_CHARACTERS_REGEX, "").toLowerCase();
975
- return allowedSchemes.includes(scheme);
976
- };
977
- //#endregion
978
- //#region src/services/sanitizeHtml/constants.ts
979
- const HTML_NAMESPACE = html$1.NS.HTML;
980
- const DEFAULT_ALLOWED_TAGS = [
981
- "address",
982
- "article",
983
- "aside",
984
- "footer",
985
- "header",
986
- "h1",
987
- "h2",
988
- "h3",
989
- "h4",
990
- "h5",
991
- "h6",
992
- "hgroup",
993
- "main",
994
- "nav",
995
- "section",
996
- "blockquote",
997
- "dd",
998
- "div",
999
- "dl",
1000
- "dt",
1001
- "figcaption",
1002
- "figure",
1003
- "hr",
1004
- "li",
1005
- "menu",
1006
- "ol",
1007
- "p",
1008
- "pre",
1009
- "ul",
1010
- "a",
1011
- "abbr",
1012
- "b",
1013
- "bdi",
1014
- "bdo",
1015
- "br",
1016
- "cite",
1017
- "code",
1018
- "data",
1019
- "dfn",
1020
- "em",
1021
- "i",
1022
- "kbd",
1023
- "mark",
1024
- "q",
1025
- "rb",
1026
- "rp",
1027
- "rt",
1028
- "rtc",
1029
- "ruby",
1030
- "s",
1031
- "samp",
1032
- "small",
1033
- "span",
1034
- "strong",
1035
- "sub",
1036
- "sup",
1037
- "time",
1038
- "u",
1039
- "var",
1040
- "wbr",
1041
- "caption",
1042
- "col",
1043
- "colgroup",
1044
- "table",
1045
- "tbody",
1046
- "td",
1047
- "tfoot",
1048
- "th",
1049
- "thead",
1050
- "tr"
1051
- ];
1052
- const DEFAULT_LINK_ATTRIBUTES = [
1053
- "href",
1054
- "name",
1055
- "target"
1056
- ];
1057
- const DEFAULT_ALLOWED_ATTRIBUTES = { a: DEFAULT_LINK_ATTRIBUTES };
1058
- const DEFAULT_ALLOWED_SCHEMES = [
1059
- "http",
1060
- "https",
1061
- "ftp",
1062
- "mailto",
1063
- "tel"
1064
- ];
1065
- const NON_TEXT_TAGS = [
1066
- "iframe",
1067
- "noembed",
1068
- "noframes",
1069
- "noscript",
1070
- "option",
1071
- "plaintext",
1072
- "script",
1073
- "style",
1074
- "textarea",
1075
- "title",
1076
- "xmp"
1077
- ];
1078
- const VOID_TAGS = [
1079
- "area",
1080
- "base",
1081
- "br",
1082
- "col",
1083
- "embed",
1084
- "hr",
1085
- "img",
1086
- "input",
1087
- "link",
1088
- "meta",
1089
- "source",
1090
- "track",
1091
- "wbr"
1092
- ];
1093
- const URL_ATTRIBUTES = [
1094
- "action",
1095
- "background",
1096
- "cite",
1097
- "data",
1098
- "formaction",
1099
- "href",
1100
- "icon",
1101
- "longdesc",
1102
- "manifest",
1103
- "poster",
1104
- "src"
1105
- ];
1106
- const SRCSET_ATTRIBUTE = "srcset";
1107
- const IMPORTANT_REGEX = /!\s*important$/iu;
1108
- const MAX_NESTING_DEPTH = 256;
1109
- const SRCSET_DESCRIPTOR_REGEX = /^(?:\d+w|\d*\.?\d+x|\d+h)$/u;
1110
- const ESCAPED_TEXT_CHARACTERS_REGEX = /[&<>]/gu;
1111
- const ESCAPED_ATTRIBUTE_CHARACTERS_REGEX = /[&"<>]/gu;
1112
- const SANITIZER_ADVISORY_WATCH_SINCE = "2026-10-11";
1113
- //#endregion
1114
- //#region src/services/sanitizeHtml/getChildNodes.ts
1115
- const getChildNodes = (element) => "content" in element ? element.content.childNodes : element.childNodes;
1116
- //#endregion
1117
- //#region src/services/sanitizeHtml/collectText.ts
1118
- const collectText = (nodes, depth) => depth > 256 ? "" : nodes.map((node) => {
1119
- if ("value" in node) return node.value;
1120
- if (!("tagName" in node) || NON_TEXT_TAGS.includes(node.tagName)) return "";
1121
- return collectText(getChildNodes(node), depth + 1);
1122
- }).join("");
1123
- //#endregion
1124
- //#region src/services/sanitizeHtml/escapeCharacters.ts
1125
- const NON_BREAKING_SPACE = String.fromCodePoint(160);
1126
- const escapeCharacters = (value, charactersRegex, entities) => value.replace(charactersRegex, (character) => entities[character] ?? character).replaceAll(NON_BREAKING_SPACE, "&nbsp;");
1127
- //#endregion
1128
- //#region src/services/sanitizeHtml/escapeAttribute.ts
1129
- const ESCAPED_ATTRIBUTE_CHARACTERS = {
1130
- "\"": "&quot;",
1131
- "&": "&amp;",
1132
- "<": "&lt;",
1133
- ">": "&gt;"
1134
- };
1135
- const escapeAttribute = (value) => escapeCharacters(value, ESCAPED_ATTRIBUTE_CHARACTERS_REGEX, ESCAPED_ATTRIBUTE_CHARACTERS);
1136
- //#endregion
1137
- //#region src/services/sanitizeHtml/escapeText.ts
1138
- const ESCAPED_TEXT_CHARACTERS = {
1139
- "&": "&amp;",
1140
- "<": "&lt;",
1141
- ">": "&gt;"
1142
- };
1143
- const escapeText = (text) => escapeCharacters(text, ESCAPED_TEXT_CHARACTERS_REGEX, ESCAPED_TEXT_CHARACTERS);
1144
- //#endregion
1145
- //#region src/services/sanitizeHtml/matchesClassPattern.ts
1146
- const matchesClassPattern = (className, pattern) => pattern.endsWith("*") ? className.startsWith(pattern.slice(0, -1)) : className === pattern;
1147
- //#endregion
1148
- //#region src/services/sanitizeHtml/filterClasses.ts
1149
- const filterClasses = (value, patterns) => {
1150
- if (!patterns) return void 0;
1151
- const classNames = value.split(/\s+/u).filter((className) => className && patterns.some((pattern) => matchesClassPattern(className, pattern)));
1152
- return classNames.length > 0 ? classNames.join(" ") : void 0;
1153
- };
1154
- //#endregion
1155
- //#region src/services/sanitizeHtml/filterSrcset.ts
1156
- const COMMA = ",";
1157
- const OPENING_PARENTHESIS = "(";
1158
- const CLOSING_PARENTHESIS = ")";
1159
- const filterSrcset = (value, allowedSchemes) => {
1160
- const candidates = [];
1161
- let position = 0;
1162
- while (position < value.length) {
1163
- while (position < value.length && (checkIsWhitespaceCharacter(value.charAt(position)) || value.charAt(position) === COMMA)) position++;
1164
- const urlStart = position;
1165
- while (position < value.length && !checkIsWhitespaceCharacter(value.charAt(position))) position++;
1166
- let url = value.slice(urlStart, position);
1167
- let descriptorText = "";
1168
- if (url.endsWith(COMMA)) url = url.replace(/,+$/u, "");
1169
- else {
1170
- const descriptorStart = position;
1171
- let isInParentheses = false;
1172
- while (position < value.length && (isInParentheses || value.charAt(position) !== COMMA)) {
1173
- if (value.charAt(position) === OPENING_PARENTHESIS) isInParentheses = true;
1174
- else if (value.charAt(position) === CLOSING_PARENTHESIS) isInParentheses = false;
1175
- position++;
1176
- }
1177
- descriptorText = value.slice(descriptorStart, position);
1178
- position++;
1179
- }
1180
- const descriptors = descriptorText.trim().split(/\s+/u).filter(Boolean);
1181
- if (!url || !checkIsAllowedUrl(url, allowedSchemes)) continue;
1182
- if (descriptors.length > 1 || descriptors.some((descriptor) => !SRCSET_DESCRIPTOR_REGEX.test(descriptor))) continue;
1183
- candidates.push([url, ...descriptors].join(" "));
1184
- }
1185
- return candidates.length > 0 ? candidates.join(", ") : void 0;
1186
- };
1187
- //#endregion
1188
- //#region src/services/sanitizeHtml/filterStyle.ts
1189
- const DECLARATION_SEPARATOR = ";";
1190
- const PROPERTY_SEPARATOR = ":";
1191
- const IMPORTANT_SUFFIX = "!important";
1192
- const filterStyle = (value, rules) => {
1193
- if (!rules) return void 0;
1194
- const declarations = /* @__PURE__ */ new Map();
1195
- for (const declaration of value.split(DECLARATION_SEPARATOR)) {
1196
- const separatorIndex = declaration.indexOf(PROPERTY_SEPARATOR);
1197
- if (separatorIndex === -1) continue;
1198
- const property = declaration.slice(0, separatorIndex).trim().toLowerCase();
1199
- if (!Object.hasOwn(rules, property)) continue;
1200
- const rawValue = declaration.slice(separatorIndex + 1).trim();
1201
- const important = IMPORTANT_REGEX.test(rawValue);
1202
- const propertyValue = rawValue.replace(IMPORTANT_REGEX, "").trim();
1203
- if (!(rules[property] ?? []).some((rule) => rule.test(propertyValue))) continue;
1204
- if (declarations.get(property)?.important && !important) continue;
1205
- declarations.set(property, {
1206
- important,
1207
- propertyValue
1208
- });
1209
- }
1210
- if (declarations.size === 0) return void 0;
1211
- return Array.from(declarations, ([property, { important, propertyValue }]) => `${property}${PROPERTY_SEPARATOR}${propertyValue}${important ? IMPORTANT_SUFFIX : ""}`).join(DECLARATION_SEPARATOR);
1212
- };
1213
- //#endregion
1214
- //#region src/services/sanitizeHtml/filterAttributes.ts
1215
- const getTagPolicy = (tagPolicies, tagName) => Object.hasOwn(tagPolicies, tagName) ? tagPolicies[tagName] : void 0;
1216
- const filterAttributes = (element, policy) => {
1217
- const { tagName } = element;
1218
- const allowedAttributes = getTagPolicy(policy.allowedAttributes, tagName) ?? [];
1219
- const isClassAllowed = Object.hasOwn(policy.allowedClasses, tagName);
1220
- const parsedAttributes = Object.fromEntries(element.attrs.map(({ name, value }) => [name, value]));
1221
- const transform = getTagPolicy(policy.transformAttributes, tagName);
1222
- const attributes = transform ? transform(parsedAttributes) : parsedAttributes;
1223
- const kept = {};
1224
- for (const [name, value] of Object.entries(attributes)) {
1225
- if (name === "class" ? !isClassAllowed : !allowedAttributes.includes(name)) continue;
1226
- const filteredValue = filterValue(tagName, name, value, policy);
1227
- if (filteredValue !== void 0) kept[name] = filteredValue;
1228
- }
1229
- return kept;
1230
- };
1231
- const filterValue = (tagName, name, value, policy) => {
1232
- if (name === "style") return filterStyle(value, getTagPolicy(policy.allowedStyles, tagName));
1233
- if (name === "class") return filterClasses(value, getTagPolicy(policy.allowedClasses, tagName));
1234
- if (name === "srcset") return filterSrcset(value, policy.allowedSchemes);
1235
- if (URL_ATTRIBUTES.includes(name)) return checkIsAllowedUrl(value, policy.allowedSchemes) ? value : void 0;
1236
- return value;
1237
- };
1238
- //#endregion
1239
- //#region src/services/sanitizeHtml/renderNode.ts
1240
- const renderNode = (node, policy, depth) => {
1241
- if (node.nodeName === "#text") return escapeText(node.value);
1242
- if (!("tagName" in node) || depth > 256) return "";
1243
- const element = node;
1244
- const children = getChildNodes(element).map((child) => renderNode(child, policy, depth + 1)).join("");
1245
- if (!(element.namespaceURI === HTML_NAMESPACE && !NON_TEXT_TAGS.includes(element.tagName) && policy.allowedTags.includes(element.tagName))) return NON_TEXT_TAGS.includes(element.tagName) ? "" : children;
1246
- const attributes = Object.entries(filterAttributes(element, policy)).map(([name, value]) => ` ${name}="${escapeAttribute(value)}"`).join("");
1247
- const opening = `<${element.tagName}${attributes}>`;
1248
- return VOID_TAGS.includes(element.tagName) ? opening : `${opening}${children}</${element.tagName}>`;
1249
- };
1250
- //#endregion
1251
- //#region src/services/sanitizeHtml/filterHtml.ts
1252
- const filterHtml = (html, policy) => {
1253
- const context = defaultTreeAdapter.createElement("body", HTML_NAMESPACE, []);
1254
- const childNodes = parseFragment(context, html, {}).childNodes;
1255
- const output = childNodes.map((node) => renderNode(node, policy, 0)).join("");
1256
- return parseFragment(context, output, {}).childNodes.map((node) => renderNode(node, policy, 0)).join("") === output ? output : escapeText(collectText(childNodes, 0));
1257
- };
1258
- //#endregion
1259
- //#region src/services/sanitizeHtml/sanitizeHtml.ts
1260
- const appendStyle = (style, declarations) => style ? `${style}; ${declarations}` : declarations;
1261
- const transformCellAlign = ({ align, ...attributes }) => align ? {
1262
- ...attributes,
1263
- style: appendStyle(attributes.style, `text-align:${align}`)
1264
- } : attributes;
1265
- const transformLink = (attributes) => ({
1266
- ...attributes,
1267
- rel: "noopener noreferrer nofollow",
1268
- target: "_blank"
1269
- });
1270
- const transformTable = (attributes) => ({
1271
- ...attributes,
1272
- style: appendStyle(attributes.style, "width:100%; border-collapse: collapse;")
1273
- });
1274
- const TEXT_ALIGN_REGEXES = [/^(?:left|right|center|justify)$/u];
1275
- const TABLE_ALLOWED_STYLES = {
1276
- table: {
1277
- "border-collapse": [/^collapse$/u],
1278
- width: [/^100%$/u]
1279
- },
1280
- td: { "text-align": TEXT_ALIGN_REGEXES },
1281
- th: { "text-align": TEXT_ALIGN_REGEXES }
1282
- };
1283
- const sanitizeHtml = (html, options) => filterHtml(html, {
1284
- allowedAttributes: {
1285
- ...options?.allowedAttributes ?? DEFAULT_ALLOWED_ATTRIBUTES,
1286
- a: [.../* @__PURE__ */ new Set([
1287
- ...options?.allowedAttributes?.a ?? DEFAULT_LINK_ATTRIBUTES,
1288
- "href",
1289
- "rel",
1290
- "target"
1291
- ])],
1292
- table: ["style"],
1293
- td: ["style"],
1294
- th: ["style"]
1295
- },
1296
- allowedClasses: options?.allowedClasses ?? {},
1297
- allowedSchemes: DEFAULT_ALLOWED_SCHEMES,
1298
- allowedStyles: {
1299
- ...options?.allowedStyles,
1300
- ...TABLE_ALLOWED_STYLES
1301
- },
1302
- allowedTags: options?.allowedTags ?? DEFAULT_ALLOWED_TAGS,
1303
- transformAttributes: {
1304
- ...options?.transformAttributes,
1305
- a: transformLink,
1306
- table: transformTable,
1307
- td: transformCellAlign,
1308
- th: transformCellAlign
1309
- }
1310
- });
1311
- //#endregion
1312
- //#region src/services/sanitizeHtml/sanitizeTextHtml.ts
1313
- const COLOR_REGEXES = [
1314
- /^#[\da-fA-F]{3,8}$/u,
1315
- /^rgba?\(\d{1,3},\s*\d{1,3},\s*\d{1,3}(?:,\s*[\d.]+)?\)$/u,
1316
- /^[a-z]+$/iu
1317
- ];
1318
- const sanitizeTextHtml = (html) => sanitizeHtml(html, {
1319
- allowedAttributes: {
1320
- input: [
1321
- "checked",
1322
- "disabled",
1323
- "type"
1324
- ],
1325
- li: ["data-checked", "data-type"],
1326
- span: [
1327
- CUSTOM_EMOJI_ID_ATTRIBUTE,
1328
- CUSTOM_EMOJI_NAME_ATTRIBUTE,
1329
- MENTION_ID_ATTRIBUTE,
1330
- MENTION_ITEM_TYPE_ATTRIBUTE,
1331
- MENTION_LABEL_ATTRIBUTE,
1332
- MENTION_TYPE_ATTRIBUTE,
1333
- SPOILER_ATTRIBUTE,
1334
- "style"
1335
- ],
1336
- ul: ["data-type"]
1337
- },
1338
- allowedClasses: {
1339
- code: ["language-*"],
1340
- pre: ["language-*"],
1341
- span: ["hljs*"]
1342
- },
1343
- allowedStyles: { span: {
1344
- "background-color": COLOR_REGEXES,
1345
- "border-radius": [/^[\d.]+(?<unit>px|em|rem|%)$/u],
1346
- color: COLOR_REGEXES
1347
- } },
1348
- allowedTags: [
1349
- ...DEFAULT_ALLOWED_TAGS,
1350
- "input",
1351
- "label"
1352
- ],
1353
- transformAttributes: { input: ({ checked }) => ({
1354
- ...checked === void 0 ? {} : { checked },
1355
- disabled: "",
1356
- type: "checkbox"
1357
- }) }
1358
- });
1359
- //#endregion
1360
- //#region src/services/shared/applyItemMetadataMixin.ts
1361
- const applyItemMetadataMixin = (Base) => class ItemWithMetadata extends Base {
1362
- createdAt = /* @__PURE__ */ new Date();
1363
- deletedAt = null;
1364
- updatedAt = /* @__PURE__ */ new Date();
1365
- };
1366
- //#endregion
1367
- //#region src/util/text/normalizeString.ts
1368
- const normalizeString = (value) => value?.trim() ?? "";
1369
- //#endregion
1370
- //#region src/services/zod/createNormalizedStringSchema.ts
1371
- const createNormalizedStringSchema = (maxLength, schema = z.string()) => schema.transform(normalizeString).pipe(z.string().max(maxLength));
1372
- //#endregion
1373
- //#region src/services/zod/createUniqueArraySchema.ts
1374
- const createUniqueArraySchema = (schema, key) => schema.array().refine((array) => new Set(key === void 0 ? array : array.map((item) => item[key])).size === array.length, "Array items must be unique");
1375
- //#endregion
1376
- //#region src/services/zstd/constants.ts
1377
- const DEFAULT_COMPRESSION_LEVEL = 12;
1378
- const MIN_WINDOW_LOG = 10;
1379
- const MAX_WINDOW_LOG = 27;
1380
- //#endregion
1381
- //#region src/services/zstd/getWindowLog.ts
1382
- const getWindowLog = (dictionaryByteCount, inputByteCount) => Math.min(27, Math.max(10, Math.ceil(Math.log2(dictionaryByteCount + inputByteCount + 1))));
1383
- //#endregion
1384
- //#region src/test/constants.ts
1385
- const ALL_SPECIAL_VALUES = [
1386
- {
1387
- isPlainObject: true,
1388
- value: {}
1389
- },
1390
- {
1391
- isPlainObject: true,
1392
- value: Object.create(null)
1393
- },
1394
- {
1395
- isPlainObject: false,
1396
- value: []
1397
- },
1398
- {
1399
- isPlainObject: false,
1400
- value: /* @__PURE__ */ new Date()
1401
- },
1402
- {
1403
- isPlainObject: false,
1404
- value: null
1405
- },
1406
- {
1407
- isPlainObject: false,
1408
- value: void 0
1409
- },
1410
- {
1411
- isPlainObject: false,
1412
- value: ""
1413
- },
1414
- {
1415
- isPlainObject: false,
1416
- value: 0
1417
- },
1418
- {
1419
- isPlainObject: false,
1420
- value: Symbol("")
1421
- },
1422
- {
1423
- isPlainObject: false,
1424
- value: noop
1425
- },
1426
- {
1427
- isPlainObject: false,
1428
- value: /(?:)/u
1429
- }
1430
- ];
1431
- //#endregion
1432
- //#region src/util/array/chunk.ts
1433
- const chunk = (array, size) => {
1434
- const chunks = [];
1435
- for (let index = 0; index < array.length; index += size) chunks.push(array.slice(index, index + size));
1436
- return chunks;
1437
- };
1438
- //#endregion
1439
- //#region src/util/array/chunkBySerializedSize.ts
1440
- const ARRAY_SERIALIZATION_BYTES = 1;
1441
- const chunkBySerializedSize = (items, maxBytes, maxCount) => {
1442
- const textEncoder = new TextEncoder();
1443
- const chunks = [];
1444
- let currentChunk = [];
1445
- let currentBytes = ARRAY_SERIALIZATION_BYTES;
1446
- for (const item of items) {
1447
- const itemBytes = textEncoder.encode(JSON.stringify(item)).length + 1;
1448
- if (currentChunk.length > 0 && (currentChunk.length === maxCount || currentBytes + itemBytes > maxBytes)) {
1449
- chunks.push(currentChunk);
1450
- currentChunk = [];
1451
- currentBytes = ARRAY_SERIALIZATION_BYTES;
1452
- }
1453
- currentChunk.push(item);
1454
- currentBytes += itemBytes;
1455
- }
1456
- if (currentChunk.length > 0) chunks.push(currentChunk);
1457
- return chunks;
1458
- };
1459
- //#endregion
1460
- //#region src/util/date/getZonedDateTime.ts
1461
- const getZonedDateTime = (date) => Temporal.Instant.fromEpochMilliseconds(date.getTime()).toZonedDateTimeISO(Temporal.Now.timeZoneId());
1462
- //#endregion
1463
- //#region src/util/date/getEndOfDay.ts
1464
- const getEndOfDay = (date) => /* @__PURE__ */ new Date(getZonedDateTime(date).startOfDay().add({ days: 1 }).epochMilliseconds - 1);
1465
- //#endregion
1466
- //#region src/util/dom/checkIsNestedInteraction.ts
1467
- const NESTED_INTERACTION_SELECTOR = [
1468
- "a[href]",
1469
- "button",
1470
- "dialog",
1471
- "input",
1472
- "label",
1473
- "select",
1474
- "summary",
1475
- "textarea",
1476
- "[contenteditable='']",
1477
- "[contenteditable='plaintext-only']",
1478
- "[contenteditable='true']",
1479
- "[data-nested-interaction]",
1480
- "[role='button']",
1481
- "[role='checkbox']",
1482
- "[role='dialog']",
1483
- "[role='link']",
1484
- "[role='menu']",
1485
- "[role='menuitem']",
1486
- "[role='option']",
1487
- "[role='switch']",
1488
- "[role='tab']"
1489
- ].join(", ");
1490
- const checkIsNestedInteraction = (event) => {
1491
- const { currentTarget, target } = event;
1492
- if (!(currentTarget instanceof Element) || !(target instanceof Element)) return false;
1493
- const interactiveElement = target.closest(NESTED_INTERACTION_SELECTOR);
1494
- if (interactiveElement && interactiveElement !== currentTarget && currentTarget.contains(interactiveElement)) return true;
1495
- else return Boolean(window.getSelection()?.toString());
1496
- };
1497
- //#endregion
1498
- //#region src/util/environment/checkIsServer.ts
1499
- const checkIsServer = () => typeof window === "undefined";
1500
- //#endregion
1501
- //#region src/util/function/getSynchronizedFunction.ts
1502
- const pendingPromises = /* @__PURE__ */ new Set();
1503
- const getSynchronizedFunction = (asyncFunction) => (...args) => {
1504
- const promise = asyncFunction(...args).finally(() => {
1505
- pendingPromises.delete(promise);
1506
- });
1507
- pendingPromises.add(promise);
1508
- };
1509
- const waitForSynchronizedFunctions = async () => {
1510
- await Promise.allSettled(pendingPromises);
1511
- };
1512
- //#endregion
1513
- //#region src/util/id/constants.ts
1514
- const ID_SEPARATOR = "|";
1515
- //#endregion
1516
- //#region src/util/id/uuid/constants.ts
1517
- const UUIDV4_REGEX = /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/iu;
1518
- //#endregion
1519
- //#region src/util/map/getOrCreate.ts
1520
- const getOrCreate = (map, key, create) => {
1521
- if (map.has(key)) return map.get(key);
1522
- const value = create();
1523
- map.set(key, value);
1524
- return value;
1525
- };
1526
- //#endregion
1527
- //#region src/util/object/checkIsCustomMethod.ts
1528
- const checkIsCustomMethod = (value, methodName) => {
1529
- const method = Reflect.get(value, methodName);
1530
- return typeof method === "function" && method !== Object.prototype[methodName];
1531
- };
1532
- //#endregion
1533
- //#region src/util/object/checkIsSameBytes.ts
1534
- const toBytes = (view) => ArrayBuffer.isView(view) ? new Uint8Array(view.buffer, view.byteOffset, view.byteLength) : new Uint8Array(view);
1535
- const checkIsSameBytes = (first, second) => {
1536
- const firstBytes = toBytes(first);
1537
- const secondBytes = toBytes(second);
1538
- return firstBytes.length === secondBytes.length && firstBytes.every((byte, index) => byte === secondBytes[index]);
1539
- };
1540
- //#endregion
1541
- //#region src/util/object/checkIsSameValueZero.ts
1542
- const checkIsSameValueZero = (first, second) => first === second || Number.isNaN(first) && Number.isNaN(second);
1543
- //#endregion
1544
- //#region src/util/object/getEnumerableKeys.ts
1545
- const getEnumerableKeys = (value) => Reflect.ownKeys(value).filter((key) => Object.prototype.propertyIsEnumerable.call(value, key));
1546
- //#endregion
1547
- //#region src/util/object/checkIsDeepEqual.ts
1548
- const checkIsBinary = (value) => ArrayBuffer.isView(value) || value instanceof ArrayBuffer || typeof SharedArrayBuffer !== "undefined" && value instanceof SharedArrayBuffer;
1549
- const checkIsDeepEqual = (first, second) => {
1550
- if (first === second) return true;
1551
- if (typeof first !== "object" || typeof second !== "object" || first === null || second === null) return checkIsSameValueZero(first, second);
1552
- if (Object.getPrototypeOf(first) !== Object.getPrototypeOf(second)) return false;
1553
- if (Array.isArray(first) || Array.isArray(second)) {
1554
- if (!Array.isArray(first) || !Array.isArray(second) || first.length !== second.length) return false;
1555
- for (const [index, item] of first.entries()) if (!checkIsDeepEqual(item, second[index])) return false;
1556
- return true;
1557
- }
1558
- if (checkIsBinary(first) && checkIsBinary(second)) return checkIsSameBytes(first, second);
1559
- if (first instanceof RegExp && second instanceof RegExp) return first.source === second.source && first.flags === second.flags;
1560
- if (first instanceof WeakMap || first instanceof WeakSet || first instanceof Promise || first instanceof Blob) return false;
1561
- if (checkIsCustomMethod(first, "valueOf") && checkIsCustomMethod(second, "valueOf")) return checkIsSameValueZero(first.valueOf(), second.valueOf());
1562
- if (checkIsCustomMethod(first, "toString") && checkIsCustomMethod(second, "toString")) return first.toString() === second.toString();
1563
- if (first instanceof Map && second instanceof Map) {
1564
- if (first.size !== second.size) return false;
1565
- for (const [key, value] of first) if (!second.has(key) || !checkIsDeepEqual(value, second.get(key))) return false;
1566
- return true;
1567
- }
1568
- if (first instanceof Set && second instanceof Set) {
1569
- if (first.size !== second.size) return false;
1570
- for (const value of first) if (!second.has(value)) return false;
1571
- return true;
1572
- }
1573
- const firstKeys = getEnumerableKeys(first);
1574
- if (firstKeys.length !== getEnumerableKeys(second).length) return false;
1575
- return firstKeys.every((key) => Object.prototype.propertyIsEnumerable.call(second, key) && checkIsDeepEqual(Reflect.get(first, key), Reflect.get(second, key)));
1576
- };
1577
- //#endregion
1578
- //#region src/util/object/checkIsPlainObject.ts
1579
- const checkIsPlainObject = (data) => {
1580
- if (typeof data !== "object" || data === null) return false;
1581
- const prototype = Object.getPrototypeOf(data);
1582
- return prototype === null || prototype === Object.prototype;
1583
- };
1584
- //#endregion
1585
- //#region src/util/object/getPropertyNames.ts
1586
- const getPropertyNames = () => new Proxy({}, { get: (_target, property) => property });
1587
- //#endregion
1588
- //#region src/util/object/jsonDateParse.ts
1589
- const ISO_DATE_REGEX = /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})T(?<hours>\d{2}):(?<minutes>\d{2}):(?<seconds>\d{2}(?:\.{0,1}\d*))(?:Z|(?<sign>\+|-)(?<offset>[\d|:]*))?$/u;
1590
- const MS_AJAX_DATE_REGEX = /^\/Date\((?<timestamp>-?\d+(?:[-+]\d+)?)\)[/\\]$/u;
1591
- const jsonDateParse = (text) => JSON.parse(text, (_key, value) => {
1592
- if (typeof value !== "string") return value;
1593
- else if (ISO_DATE_REGEX.test(value)) return new Date(value);
1594
- const msAjaxDateMatch = MS_AJAX_DATE_REGEX.exec(value);
1595
- if (!msAjaxDateMatch) return value;
1596
- const timestampParts = takeOne(msAjaxDateMatch, 1).split(/[-+,.]/u);
1597
- return new Date(timestampParts[0] ? Number(timestampParts[0]) : 0 - Number(timestampParts[1]));
1598
- });
1599
- //#endregion
1600
- //#region src/util/object/mergeObjectsStrict.ts
1601
- const mergeObjectsStrict = (...objects) => Object.assign({}, ...objects);
1602
- //#endregion
1603
- //#region src/util/object/omitDeep.ts
1604
- const checkIsWalkable = (value) => Object.prototype.toString.call(value) === "[object Object]";
1605
- const omitValue = (value, omittedKeys) => {
1606
- if (Array.isArray(value)) return value.map((element) => omitValue(element, omittedKeys));
1607
- if (!checkIsWalkable(value)) return value;
1608
- const omittedValue = {};
1609
- for (const [key, propertyValue] of Object.entries(value)) if (!omittedKeys.has(key)) omittedValue[key] = omitValue(propertyValue, omittedKeys);
1610
- return omittedValue;
1611
- };
1612
- const omitDeep = (value, ...keys) => omitValue(value, new Set(keys));
1613
- //#endregion
1614
- //#region src/util/promise/createEvictingPromiseCache.ts
1615
- const createEvictingPromiseCache = (getKey, load) => {
1616
- const promiseMap = /* @__PURE__ */ new Map();
1617
- return (...args) => {
1618
- const key = getKey(...args);
1619
- const promise = promiseMap.get(key) ?? load(...args);
1620
- promiseMap.set(key, promise);
1621
- return getResultAsync(() => promise).match((value) => value, (error) => {
1622
- if (promiseMap.get(key) === promise) promiseMap.delete(key);
1623
- throw error;
1624
- });
1625
- };
1626
- };
1627
- //#endregion
1628
- //#region src/util/promise/settleAll.ts
1629
- const settleAll = async (tasks, concurrencyLimit = tasks.length) => {
1630
- if (tasks.length === 0) return [];
1631
- const values = [];
1632
- for (const tasksChunk of chunk(tasks, concurrencyLimit)) {
1633
- const results = await Promise.allSettled(tasksChunk.map((task) => Promise.try(task)));
1634
- const reasons = [];
1635
- for (const result of results) if (result.status === "rejected") reasons.push(result.reason);
1636
- else values.push(result.value);
1637
- if (reasons.length === 1) throw takeOne(reasons);
1638
- else if (reasons.length > 1) throw new AggregateError(reasons, toAppError(takeOne(reasons)).message);
1639
- }
1640
- return values;
1641
- };
1642
- //#endregion
1643
- //#region src/util/text/capitalize.ts
1644
- const capitalize = (string) => `${string.charAt(0).toUpperCase()}${string.slice(1)}`;
1645
- //#endregion
1646
- //#region src/util/text/dedent.ts
1647
- const ESCAPE_CHARACTER = "\\";
1648
- const LINE_FEED = "\n";
1649
- const LINE_FEED_CHARACTER = {
1650
- escapable: false,
1651
- value: LINE_FEED
1652
- };
1653
- const HEXADECIMAL_REGEX = /^[\da-fA-F]$/u;
1654
- const WHITESPACE_REGEX = /^\s$/u;
1655
- const BRACED_CODE_POINT_MAXIMUM_DIGITS = 6;
1656
- const CODE_POINT_MAXIMUM = 1114111;
1657
- const HEXADECIMAL_BYTE_DIGITS = 2;
1658
- const HEXADECIMAL_UNIT_DIGITS = 4;
1659
- const escapeValueMap = {
1660
- "0": "\0",
1661
- $: "$",
1662
- "\\": "\\",
1663
- "`": "`",
1664
- b: "\b",
1665
- f: "\f",
1666
- n: "\n",
1667
- r: "\r",
1668
- t: " ",
1669
- v: "\v",
1670
- "{": "{"
1671
- };
1672
- const toCharacters = (text, escapable) => text.split("").map((value) => ({
1673
- escapable,
1674
- value
1675
- }));
1676
- const isWhitespace = (character) => WHITESPACE_REGEX.test(character.value);
1677
- const alignValue = (value, precedingText) => {
1678
- const currentLine = precedingText.slice(precedingText.lastIndexOf(LINE_FEED) + 1);
1679
- const indentation = /^\s+/u.exec(currentLine)?.[0];
1680
- return indentation ? value.replaceAll(LINE_FEED, `${LINE_FEED}${indentation}`) : value;
1681
- };
1682
- const isEscapeStart = (characters, index) => {
1683
- const character = characters[index];
1684
- const next = characters[index + 1];
1685
- return character?.escapable === true && character.value === ESCAPE_CHARACTER && next?.escapable === true;
1686
- };
1687
- const removeLineContinuations = (characters) => {
1688
- const result = [];
1689
- let index = 0;
1690
- while (index < characters.length) {
1691
- const character = characters[index];
1692
- if (!character) break;
1693
- if (isEscapeStart(characters, index)) {
1694
- const next = characters[index + 1];
1695
- if (next?.value === LINE_FEED) {
1696
- index += 2;
1697
- while (characters[index]?.escapable === true && (characters[index]?.value === " " || characters[index]?.value === " ")) index++;
1698
- } else {
1699
- result.push(character, ...next ? [next] : []);
1700
- index += 2;
1701
- }
1702
- } else {
1703
- result.push(character);
1704
- index++;
1705
- }
1706
- }
1707
- return result;
1708
- };
1709
- const splitLines = (characters) => {
1710
- const lines = [];
1711
- let line = [];
1712
- for (const character of characters) if (character.value === LINE_FEED) {
1713
- lines.push(line);
1714
- line = [];
1715
- } else line.push(character);
1716
- lines.push(line);
1717
- return lines;
1718
- };
1719
- const getIndentation = (line) => {
1720
- const indentation = line.findIndex((character) => !isWhitespace(character));
1721
- return indentation > 0 ? indentation : void 0;
1722
- };
1723
- const dedentCharacters = (characters) => {
1724
- const lines = splitLines(characters);
1725
- const indentations = lines.map((line) => getIndentation(line)).filter((indentation) => indentation !== void 0);
1726
- if (indentations.length === 0) return characters;
1727
- const minimumIndentation = Math.min(...indentations);
1728
- const result = [];
1729
- for (const [index, line] of lines.entries()) {
1730
- if (index > 0) result.push(LINE_FEED_CHARACTER);
1731
- const first = line[0]?.value;
1732
- result.push(...first === " " || first === " " ? line.slice(minimumIndentation) : line);
1733
- }
1734
- return result;
1735
- };
1736
- const trimCharacters = (characters) => {
1737
- const start = characters.findIndex((character) => !isWhitespace(character));
1738
- if (start === -1) return [];
1739
- return characters.slice(start, characters.findLastIndex((character) => !isWhitespace(character)) + 1);
1740
- };
1741
- const readHexadecimal = (characters, start, digits) => {
1742
- let hexadecimal = "";
1743
- for (let index = start; index < start + digits; index++) {
1744
- const character = characters[index];
1745
- if (character?.escapable !== true || !HEXADECIMAL_REGEX.test(character.value)) return void 0;
1746
- hexadecimal += character.value;
1747
- }
1748
- return hexadecimal;
1749
- };
1750
- const readBracedCodePoint = (characters, index) => {
1751
- if (characters[index + 2]?.value !== "{") return void 0;
1752
- let digits = "";
1753
- let cursor = index + 3;
1754
- while (digits.length < BRACED_CODE_POINT_MAXIMUM_DIGITS && HEXADECIMAL_REGEX.test(characters[cursor]?.value ?? "")) {
1755
- digits += characters[cursor]?.value;
1756
- cursor++;
1757
- }
1758
- const closing = characters[cursor];
1759
- if (digits.length === 0 || closing?.escapable !== true || closing.value !== "}") return void 0;
1760
- const codePoint = Number.parseInt(digits, 16);
1761
- if (codePoint > CODE_POINT_MAXIMUM) return void 0;
1762
- return {
1763
- length: cursor - index + 1,
1764
- text: String.fromCodePoint(codePoint)
1765
- };
1766
- };
1767
- const fromHexadecimal = (hexadecimal) => String.fromCodePoint(Number.parseInt(hexadecimal, 16));
1768
- const readEscape = (characters, index) => {
1769
- const character = characters[index];
1770
- if (!character) return {
1771
- length: 0,
1772
- text: ""
1773
- };
1774
- if (!isEscapeStart(characters, index)) return {
1775
- length: 1,
1776
- text: character.value
1777
- };
1778
- const next = characters[index + 1];
1779
- const escapeValue = next ? escapeValueMap[next.value] : void 0;
1780
- if (escapeValue !== void 0) return {
1781
- length: 2,
1782
- text: escapeValue
1783
- };
1784
- if (next?.value === "x") {
1785
- const hexadecimal = readHexadecimal(characters, index + 2, HEXADECIMAL_BYTE_DIGITS);
1786
- if (hexadecimal !== void 0) return {
1787
- length: 4,
1788
- text: fromHexadecimal(hexadecimal)
1789
- };
1790
- }
1791
- if (next?.value === "u") {
1792
- const braced = readBracedCodePoint(characters, index);
1793
- if (braced) return braced;
1794
- const hexadecimal = readHexadecimal(characters, index + 2, HEXADECIMAL_UNIT_DIGITS);
1795
- if (hexadecimal !== void 0) return {
1796
- length: 6,
1797
- text: fromHexadecimal(hexadecimal)
1798
- };
1799
- }
1800
- return {
1801
- length: 1,
1802
- text: character.value
1803
- };
1804
- };
1805
- const cookCharacters = (characters) => {
1806
- let result = "";
1807
- let index = 0;
1808
- while (index < characters.length) {
1809
- const cooked = readEscape(characters, index);
1810
- result += cooked.text;
1811
- index += cooked.length;
1812
- }
1813
- return result;
1814
- };
1815
- const createDedent = (options) => {
1816
- const dedent = (strings, ...values) => {
1817
- const isTemplate = typeof strings !== "string";
1818
- const raws = isTemplate ? strings.raw : [strings];
1819
- const { alignValues = false, escapeSpecialCharacters = isTemplate, trimWhitespace = true } = options;
1820
- let precedingText = "";
1821
- const parts = [];
1822
- for (const [index, raw] of raws.entries()) {
1823
- parts.push(toCharacters(raw, true));
1824
- precedingText += raw;
1825
- if (index < values.length) {
1826
- const value = String(values[index]);
1827
- const alignedValue = alignValues ? alignValue(value, precedingText) : value;
1828
- parts.push(toCharacters(alignedValue, false));
1829
- precedingText += alignedValue;
1830
- }
1831
- }
1832
- let characters = parts.flat();
1833
- if (escapeSpecialCharacters) characters = removeLineContinuations(characters);
1834
- characters = dedentCharacters(characters);
1835
- if (trimWhitespace) characters = trimCharacters(characters);
1836
- return escapeSpecialCharacters ? cookCharacters(characters) : characters.map((character) => character.value).join("");
1837
- };
1838
- dedent.withOptions = (newOptions) => createDedent({
1839
- ...options,
1840
- ...newOptions
1841
- });
1842
- return dedent;
1843
- };
1844
- const dedent = createDedent({});
1845
- //#endregion
1846
- //#region src/util/text/encodeUrlSubDelimiters.ts
1847
- const EncodedSubDelimiterMap = {
1848
- "!": "%21",
1849
- "'": "%27",
1850
- "(": "%28",
1851
- ")": "%29",
1852
- "*": "%2A"
1853
- };
1854
- const encodeUrlSubDelimiters = (value) => Object.entries(EncodedSubDelimiterMap).reduce((encoded, [subDelimiter, encodedSubDelimiter]) => encoded.replaceAll(subDelimiter, encodedSubDelimiter), value);
1855
- //#endregion
1856
- //#region src/util/text/getDecodedUriComponent.ts
1857
- const getDecodedUriComponent = (value, fallback) => getResult(() => decodeURIComponent(value)).unwrapOr(fallback);
1858
- //#endregion
1859
- //#region src/util/text/streamToText.ts
1860
- const streamToText = async (readable) => {
1861
- readable.setEncoding("utf8");
1862
- let data = "";
1863
- for await (const chunk of readable) data += chunk.toString();
1864
- return data;
1865
- };
1866
- //#endregion
1867
- //#region src/util/text/toKebabCase.ts
1868
- const toKebabCase = (string) => string.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/gu)?.map((x) => x.toLowerCase()).join("-") ?? "";
1869
- //#endregion
1870
- //#region src/util/text/truncate.ts
1871
- const SUFFIX = "...";
1872
- const truncate = (string, length) => {
1873
- if (string.length <= length) return string;
1874
- else if (length < 3) return string.slice(0, length);
1875
- else return `${string.slice(0, length - 3)}${SUFFIX}`;
1876
- };
1877
- //#endregion
1878
- //#region src/util/text/uncapitalize.ts
1879
- const uncapitalize = (string) => `${string.charAt(0).toLowerCase()}${string.slice(1)}`;
1880
- //#endregion
1881
- //#region src/util/time/hrtime.ts
1882
- const hrtime = (previousHrTime) => {
1883
- if (checkIsServer()) return process.hrtime(previousHrTime);
1884
- const clocktime = performance.now() * .001;
1885
- let seconds = Math.floor(clocktime);
1886
- let nanoseconds = Math.floor(clocktime % 1 * 1e9);
1887
- if (previousHrTime) {
1888
- seconds -= previousHrTime[0];
1889
- nanoseconds -= previousHrTime[1];
1890
- if (nanoseconds < 0) {
1891
- seconds--;
1892
- nanoseconds += 1e9;
1893
- }
1894
- }
1895
- return [seconds, nanoseconds];
1896
- };
1897
- //#endregion
1898
- //#region src/util/time/now.ts
1899
- const loadNanoseconds = hrtime();
1900
- const loadMilliseconds = Date.now();
1901
- const now = () => {
1902
- const [seconds, nanoseconds] = hrtime(loadNanoseconds);
1903
- return (BigInt(loadMilliseconds) * 10n ** 6n + (BigInt(seconds) * 10n ** 9n + BigInt(nanoseconds))).toString();
1904
- };
1905
- //#endregion
1906
- //#region src/util/time/sleep.ts
1907
- const sleep = (durationMs) => new Promise((resolve) => {
1908
- setTimeout(() => {
1909
- resolve();
1910
- }, durationMs);
1911
- });
1912
- //#endregion
1913
- //#region src/util/validation/exhaustiveGuard.ts
1914
- const exhaustiveGuard = (value) => {
1915
- throw new InvalidOperationError("Read", exhaustiveGuard.name, JSON.stringify(value));
1916
- };
1917
- //#endregion
1918
- export { ALL_SPECIAL_VALUES, CHARSET_PARAMETER_REGEX, CUSTOM_EMOJI_ID_ATTRIBUTE, CUSTOM_EMOJI_NAME_ATTRIBUTE, DEFAULT_ALLOWED_ATTRIBUTES, DEFAULT_ALLOWED_SCHEMES, DEFAULT_ALLOWED_TAGS, DEFAULT_COMPRESSION_LEVEL, DEFAULT_FACET_SCORE, DEFAULT_LINK_ATTRIBUTES, DEFAULT_SOURCE_SCORE, DEFAULT_TEXT_CHARSET, DEFAULT_TYPE_SCORE, ESCAPED_ATTRIBUTE_CHARACTERS_REGEX, ESCAPED_TEXT_CHARACTERS_REGEX, FacetScoreMap, ForbiddenError, GIBIBYTE, HTML_NAMESPACE, ID_SEPARATOR, IMPORTANT_REGEX, InvalidOperationError, ItemMetadata, KIBIBYTE, MAX_NESTING_DEPTH, MAX_READ_LIMIT, MAX_WINDOW_LOG, MEDIA_TYPE_REGEX, MENTION_EVERYONE_ID, MENTION_HERE_ID, MENTION_ID_ATTRIBUTE, MENTION_ITEM_TYPE_ATTRIBUTE, MENTION_LABEL_ATTRIBUTE, MENTION_SELECTOR, MENTION_TYPE, MENTION_TYPE_ATTRIBUTE, MIN_WINDOW_LOG, MentionType, NON_TEXT_TAGS, NotFoundError, NotInitializedError, ObjectMethod, Operation, PATH_SEPARATOR_REGEX, RoutePath, SANITIZER_ADVISORY_WATCH_SINCE, SITE_NAME, SPOILER_ATTRIBUTE, SPOILER_SELECTOR, SRCSET_ATTRIBUTE, SRCSET_DESCRIPTOR_REGEX, Serializable, SourceScoreMap, TEXT_MEDIA_TYPE_REGEX, TypeScoreMap, TypedEventEmitter, URL_ATTRIBUTES, UUIDV4_REGEX, VOID_TAGS, WordFilteredError, applyItemMetadataMixin, capitalize, charset, checkContainsProfanity, checkIsAllowedUrl, checkIsCustomMethod, checkIsDeepEqual, checkIsNestedInteraction, checkIsPlainObject, checkIsSameBytes, checkIsSameValueZero, checkIsServer, checkIsUnsafeUrlCharacter, checkIsWhitespaceCharacter, chunk, chunkBySerializedSize, collectText, contentType, createEvictingPromiseCache, createItemEntityTypeSchema, createNormalizedStringSchema, createUniqueArraySchema, css, dedent, encodeUrlSubDelimiters, englishProfaneWords, escapeAttribute, escapeCharacters, escapeText, exhaustiveGuard, extension, filterAttributes, filterClasses, filterHtml, filterSrcset, filterStyle, getChildNodes, getDecodedUriComponent, getEndOfDay, getEnumerableKeys, getExtensionMimeTypeMap, getMediaType, getMentions, getMimeScore, getMimeTypeEntryMap, getOrCreate, getPropertyNames, getRawData, getRequestError, getResult, getResultAsync, getSynchronizedFunction, getTransactionDone, getTransactionObjectStore, getWindowLog, getZonedDateTime, hrtime, html, jsonDateParse, lookup, matchesClassPattern, mergeObjectsStrict, noop, normalizeString, now, omitDeep, openDatabase, renderNode, reportFinalizerError, requestToPromise, sanitizeHtml, sanitizeTextHtml, settleAll, sleep, streamToText, takeOne, toAppError, toKebabCase, toRawDeep, truncate, uncapitalize, waitForSynchronizedFunctions, withFinalizer, withFinalizerAsync, wrapDatabase, wrapIndex, wrapObjectStore, wrapTransaction, wrapUpgradeDatabase, wrapUpgradeTransaction };