Move to some etension methods

This commit is contained in:
Rory& 2025-09-21 21:51:17 +02:00
parent 0d907af72f
commit bd9a75f919
10 changed files with 125 additions and 69 deletions

View File

@ -18,7 +18,6 @@
// process.env.MONGOMS_DEBUG = "true";
import moduleAlias from "module-alias";
moduleAlias(__dirname + "../../../package.json");
import "reflect-metadata";

View File

@ -566,7 +566,7 @@ export class Channel extends BaseClass {
let userPerms = new Permissions(new BitField(0).add(roles.map(r => r.permissions)));
// TODO: do we want to have an instance-wide opt out of this behavior? It would just be an extra if statement here
if (userPerms.has(Permissions.FLAGS.ADMINISTRATOR)) return true;
if (userPerms.has(Permissions.FLAGS.ADMINISTRATOR)) return userPerms;
// apply channel overrides
if (this.permission_overwrites) {

View File

@ -1,31 +0,0 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// TODO: remove this function.
export function containsAll(arr: unknown[], target: unknown[]) {
return target.every((v) => arr.includes(v));
}
/* https://stackoverflow.com/a/50636286 */
export function partition<T>(array: T[], filter: (elem: T) => boolean) {
const pass: T[] = [],
fail: T[] = [];
array.forEach((e) => (filter(e) ? pass : fail).push(e));
return [pass, fail];
}

View File

@ -1,32 +0,0 @@
/**
* Normalize a URL by:
* - Removing trailing slashes (except root path)
* - Sorting query params alphabetically
* - Removing empty query strings
* - Removing fragments
*/
export function normalizeUrl(input: string): string {
try {
const u = new URL(input);
// Remove fragment
u.hash = "";
// Normalize pathname - remove trailing slash except for root "/"
if (u.pathname !== "/" && u.pathname.endsWith("/")) {
u.pathname = u.pathname.slice(0, -1);
}
// Normalize query params: sort by key
if (u.search) {
const params = Array.from(u.searchParams.entries());
params.sort(([a], [b]) => a.localeCompare(b));
u.search = params.length
? "?" + params.map(([k, v]) => `${k}=${v}`).join("&")
: "";
} else {
// Ensure no empty search string
u.search = "";
}
return u.toString();
} catch (e) {
return input;
}
}

View File

@ -0,0 +1,58 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2025 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare global {
interface Array<T> {
containsAll(target: T[]): boolean;
partition(filter: (elem: T) => boolean): [T[], T[]];
single(filter: (elem: T) => boolean): T | null;
}
}
export function containsAll<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[]] {
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 {
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];
}
// register extensions
if (!Array.prototype.containsAll)
Array.prototype.containsAll = function <T>(this: T[], target: T[]) {
return containsAll(this, target);
};
if (!Array.prototype.partition)
Array.prototype.partition = function <T>(this: T[], filter: (elem: T) => boolean) {
return partition(this, filter);
};
if (!Array.prototype.single)
Array.prototype.single = function <T>(this: T[], filter: (elem: T) => boolean) {
return single(this, filter);
};

0
src/util/util/extensions/Url.d.ts vendored Normal file
View File

View File

@ -0,0 +1,60 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2025 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare module "url" {
interface URL {
normalize(): string;
}
}
/**
* Normalize a URL by:
* - Removing trailing slashes (except root path)
* - Sorting query params alphabetically
* - Removing empty query strings
* - Removing fragments
*/
export function normalizeUrl(input: string): string {
try {
const u = new URL(input);
// Remove fragment
u.hash = "";
// Normalize pathname - remove trailing slash except for root "/"
if (u.pathname !== "/" && u.pathname.endsWith("/")) {
u.pathname = u.pathname.slice(0, -1);
}
// Normalize query params: sort by key
if (u.search) {
const params = Array.from(u.searchParams.entries());
params.sort(([a], [b]) => a.localeCompare(b));
u.search = params.length ? "?" + params.map(([k, v]) => `${k}=${v}`).join("&") : "";
} else {
// Ensure no empty search string
u.search = "";
}
return u.toString();
} catch (e) {
return input;
}
}
// register extensions
if (!URL.prototype.normalize)
URL.prototype.normalize = function () {
return normalizeUrl(this.toString());
};

View File

@ -0,0 +1,2 @@
export * from "./Array";
export * from "./Url";

View File

@ -17,7 +17,7 @@
*/
export * from "./ApiError";
export * from "./Array";
export * from "./extensions/Array";
export * from "./BitField";
//export * from "./Categories";
export * from "./cdn";
@ -44,8 +44,8 @@ export * from "./String";
export * from "./Token";
export * from "./TraverseDirectory";
export * from "./WebAuthn";
export * from "./Url";
export * from "./Gifs";
export * from "./Application";
export * from "./NameValidation";
export * from "./HelperTypes";
export * from "./extensions";

View File

@ -55,8 +55,8 @@
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
"declaration": false /* Generate .d.ts files from TypeScript and JavaScript files in your project. */,
"declarationMap": false /* Create sourcemaps for d.ts files. */,
"declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */,
"declarationMap": true /* Create sourcemaps for d.ts files. */,
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
"sourceMap": true /* Create source map files for emitted JavaScript files. */,
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */