Clean up array extensions

This commit is contained in:
Rory& 2025-10-03 20:50:48 +02:00
parent 8bd0d5c06b
commit a25393e806
10 changed files with 76 additions and 34 deletions

View File

@ -118,7 +118,7 @@
"@spacebar/gateway": "dist/gateway",
"@spacebar/util": "dist/util",
"@spacebar/webrtc": "dist/webrtc",
"lambert-server": "dist/util/util/lambert-server"
"lambert-server": "dist/util/util/lambert-server"
},
"optionalDependencies": {
"@sendgrid/mail": "^8.1.6",

View File

@ -51,7 +51,7 @@ router.put(
const recipients = [
...(channel.recipients?.map((r) => r.user_id) || []),
user_id,
].unique();
].distinct();
const new_channel = await Channel.createDMChannel(
recipients,

View File

@ -35,7 +35,7 @@ router.post(
async (req: Request, res: Response) => {
const { channel_id } = req.params;
const user_id = req.user_id;
const timestamp = Date.nowSeconds();
const timestamp = Math.floor(Date.now() / 1000);
const channel = await Channel.findOneOrFail({
where: { id: channel_id },
});

View File

@ -17,7 +17,7 @@
*/
import { Router, Request, Response } from "express";
import { DiscordApiErrors, Member, partition } from "@spacebar/util";
import { DiscordApiErrors, Member } from "@spacebar/util";
import { route } from "@spacebar/api";
const router = Router({ mergeParams: true });
@ -38,8 +38,7 @@ router.patch(
relations: ["roles"],
});
const [add, remove] = partition(
members,
const [add, remove] = members.partition(
(member) =>
member_ids.includes(member.id) &&
!member.roles.map((role) => role.id).includes(role_id),

View File

@ -20,7 +20,7 @@ import { Config } from "@spacebar/util";
const reNUMBER = /[0-9]/g;
const reUPPERCASELETTER = /[A-Z]/g;
const reSYMBOLS = /[A-Z,a-z,0-9]/g;
const reSYMBOLS = /[A-Za-z0-9]/g;
// const blocklist: string[] = []; // TODO: update ones passwordblocklist is stored in db
/*
@ -45,12 +45,12 @@ export function checkPassword(password: string): number {
}
// checks for amount of Numbers
if (password.count(reNUMBER) >= minNumbers - 1) {
if (password.match(reNUMBER)?.length ?? 0 >= minNumbers - 1) {
strength += 0.05;
}
// checks for amount of Uppercase Letters
if (password.count(reUPPERCASELETTER) >= minUpperCase - 1) {
if (password.match(reUPPERCASELETTER)?.length ?? 0 >= minUpperCase - 1) {
strength += 0.05;
}
@ -61,8 +61,8 @@ export function checkPassword(password: string): number {
// checks if password only consists of numbers or only consists of chars
if (
password.length == password.count(reNUMBER) ||
password.length === password.count(reUPPERCASELETTER)
password.length == password.match(reNUMBER)?.length ||
password.length === password.match(reUPPERCASELETTER)?.length
) {
strength = 0;
}

View File

@ -26,7 +26,6 @@ import {
LazyRequestSchema,
User,
Presence,
partition,
Channel,
Permissions,
} from "@spacebar/util";
@ -108,7 +107,7 @@ async function getMembers(guild_id: string, range: [number, number]) {
const member_roles = members
.map((m) => m.roles)
.flat()
.unique((r: Role) => r.id);
.distinctBy((r: Role) => r.id);
member_roles.push(
member_roles.splice(
member_roles.findIndex((x) => x.id === x.guild_id),
@ -119,8 +118,7 @@ async function getMembers(guild_id: string, range: [number, number]) {
const offlineItems = [];
for (const role of member_roles) {
const [role_members, other_members] = partition(
members,
const [role_members, other_members] = members.partition(
(m: Member) => !!m.roles.find((r) => r.id === role.id),
);
const group = {
@ -284,9 +282,9 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
channel.permission_overwrites.forEach((overwrite) => {
const { id, allow, deny } = overwrite;
if (allow.toBigInt() & Permissions.FLAGS.VIEW_CHANNEL)
if (BigInt(allow) & Permissions.FLAGS.VIEW_CHANNEL)
perms.push(`allow:${id}`);
else if (deny.toBigInt() & Permissions.FLAGS.VIEW_CHANNEL)
else if (BigInt(deny) & Permissions.FLAGS.VIEW_CHANNEL)
perms.push(`deny:${id}`);
});
@ -307,7 +305,7 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
const groups = ops
.map((x) => x.groups)
.flat()
.unique();
.distinct();
await Send(this, {
op: OPCODES.Dispatch,

View File

@ -27,7 +27,7 @@ import {
} from "typeorm";
import { DmChannelDTO } from "../dtos";
import { ChannelCreateEvent, ChannelRecipientRemoveEvent } from "../interfaces";
import { InvisibleCharacters, Snowflake, containsAll, emitEvent, getPermission, trimSpecial, Permissions, BitField } from "../util";
import { InvisibleCharacters, Snowflake, emitEvent, getPermission, trimSpecial, Permissions, BitField } from "../util";
import { BaseClass } from "./BaseClass";
import { Guild } from "./Guild";
import { Invite } from "./Invite";
@ -328,7 +328,7 @@ export class Channel extends BaseClass {
creator_user_id: string,
name?: string,
) {
recipients = recipients.unique().filter((x) => x !== creator_user_id);
recipients = recipients.distinct().filter((x) => x !== creator_user_id);
// TODO: check config for max number of recipients
/** if you want to disallow note to self channels, uncomment the conditional below
@ -354,7 +354,7 @@ export class Channel extends BaseClass {
if (!ur.channel.recipients) continue;
const re = ur.channel.recipients.map((r) => r.user_id);
if (re.length === channelRecipients.length) {
if (containsAll(re, channelRecipients)) {
if (re.containsAll(channelRecipients)) {
if (channel == null) {
channel = ur.channel;
await ur.assign({ closed: false }).save();

View File

@ -56,9 +56,9 @@ export function enableAutoUpdate(opts: {
const latestVersion = await getLatestVersion(opts.packageJsonLink);
if (currentVersion !== latestVersion) {
rl.question(
`[Auto Update] Current version (${currentVersion}) is out of date, would you like to update? (yes/no)`,
`[Auto Update] Current version (${currentVersion}) is out of date, would you like to update? (Y/n)`,
(answer) => {
if (answer.toBoolean()) {
if (answer === "" || answer.toLowerCase() === "y") {
console.log(`[Auto update] updating ...`);
download(opts.downloadUrl, opts.path);
} else {

View File

@ -23,7 +23,7 @@ export function FieldErrors(
return new FieldError(
50035,
"Invalid Form Body",
fields.map(({ message, code }) => ({
(fields as Object).map(({ message, code }) => ({
_errors: [
{
message,

View File

@ -23,57 +23,102 @@ declare global {
single(filter: (elem: T) => boolean): T | null;
forEachAsync(callback: (elem: T, index: number, array: T[]) => Promise<void>): Promise<void>;
remove(item: T): void;
first(): T | undefined;
last(): T | undefined;
distinct(): T[];
distinctBy<K>(key: (elem: T) => K): T[];
}
}
export function containsAll<T>(arr: T[], target: T[]) {
export function arrayContainsAll<T>(arr: T[], target: T[]) {
return target.every((v) => arr.includes(v));
}
/* https://stackoverflow.com/a/50636286 */
export function partition<T>(array: T[], filter: (elem: T) => boolean): [T[], T[]] {
export function arrayPartition<T>(array: T[], filter: (elem: T) => boolean): [T[], T[]] {
const pass: T[] = [],
fail: T[] = [];
array.forEach((e) => (filter(e) ? pass : fail).push(e));
return [pass, fail];
}
export function single<T>(array: T[], filter: (elem: T) => boolean): T | null {
export function arraySingle<T>(array: T[], filter: (elem: T) => boolean): T | null {
const results = array.filter(filter);
if (results.length > 1) throw new Error("Array contains more than one matching element");
if (results.length === 0) return null;
return results[0];
}
export async function forEachAsync<T>(array: T[], callback: (elem: T, index: number, array: T[]) => Promise<void>): Promise<void> {
export async function arrayForEachAsync<T>(array: T[], callback: (elem: T, index: number, array: T[]) => Promise<void>): Promise<void> {
await Promise.all(array.map(callback));
}
export function remove<T>(this: T[], item: T): void {
export function arrayRemove<T>(this: T[], item: T): void {
const index = this.indexOf(item);
if (index > -1) {
this.splice(index, 1);
}
}
export function arrayFirst<T>(this: T[]): T | undefined {
return this[0];
}
export function arrayLast<T>(this: T[]): T | undefined {
return this[this.length - 1];
}
export function arrayDistinct<T>(this: T[]): T[] {
return Array.from(new Set(this));
}
export function arrayDistinctBy<T, K>(this: T[], key: (elem: T) => K): T[] {
const seen = new Set<K>();
return this.filter((item) => {
const k = key(item);
if (seen.has(k)) {
return false;
} else {
seen.add(k);
return true;
}
});
}
// register extensions
if (!Array.prototype.containsAll)
Array.prototype.containsAll = function <T>(this: T[], target: T[]) {
return containsAll(this, target);
return arrayContainsAll(this, target);
};
if (!Array.prototype.partition)
Array.prototype.partition = function <T>(this: T[], filter: (elem: T) => boolean) {
return partition(this, filter);
return arrayPartition(this, filter);
};
if (!Array.prototype.single)
Array.prototype.single = function <T>(this: T[], filter: (elem: T) => boolean) {
return single(this, filter);
return arraySingle(this, filter);
};
if (!Array.prototype.forEachAsync)
Array.prototype.forEachAsync = function <T>(this: T[], callback: (elem: T, index: number, array: T[]) => Promise<void>) {
return forEachAsync(this, callback);
return arrayForEachAsync(this, callback);
};
if (!Array.prototype.remove)
Array.prototype.remove = function <T>(this: T[], item: T) {
return remove.call(this, item);
return arrayRemove.call(this, item);
};
if (!Array.prototype.first)
Array.prototype.first = function <T>(this: T[]) {
return arrayFirst.call(this);
};
if (!Array.prototype.last)
Array.prototype.last = function <T>(this: T[]) {
return arrayLast.call(this);
};
if (!Array.prototype.distinct)
Array.prototype.distinct = function <T>(this: T[]) {
return arrayDistinct.call(this);
};
if (!Array.prototype.distinctBy)
Array.prototype.distinctBy = function <T, K>(this: T[], key: (elem: T) => K) {
return arrayDistinctBy.call(this, key as ((elem: unknown) => unknown));
};