chore: ChangeReporter webhook support

This commit is contained in:
ryan-0324 2024-07-08 18:06:55 -04:00
parent 3913cc6f6b
commit 627ee47725
12 changed files with 659 additions and 551 deletions

View file

@ -53,8 +53,8 @@
"@types/react": "~18.2.79",
"@types/react-dom": "~18.2.25",
"@types/yazl": "^2.4.5",
"@typescript-eslint/eslint-plugin": "^7.15.0",
"@typescript-eslint/parser": "^7.15.0",
"@typescript-eslint/eslint-plugin": "^7.16.0",
"@typescript-eslint/parser": "^7.16.0",
"@vencord/discord-types": "workspace:^",
"diff": "^5.2.0",
"discord-types": "^1.3.3",

View file

@ -33,7 +33,7 @@
"@stylistic/eslint-plugin": "^2.3.0",
"@types/node": "^20.14.10",
"@types/semver": "^7.5.8",
"@typescript-eslint/typescript-estree": "^8.0.0-alpha.39",
"@typescript-eslint/typescript-estree": "^8.0.0-alpha.41",
"eslint": "^9.6.0",
"eslint-plugin-check-file": "^2.8.0",
"eslint-plugin-headers": "^1.1.2",
@ -45,6 +45,6 @@
"semver": "^7.6.2",
"tsx": "^4.16.2",
"typescript": "^5.5.3",
"typescript-eslint": "^8.0.0-alpha.39"
"typescript-eslint": "^8.0.0-alpha.41"
}
}

View file

@ -0,0 +1,372 @@
/*
* discord-types
* Copyright (C) 2024 Vencord project contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
// eslint-disable-next-line import/no-relative-packages
import type * as Vencord from "../../../../src/Vencord.ts";
import type { CR } from "./types.mts";
export function autoFindStore(this: typeof Vencord, name: string, source: CR.ClassMembers) {
const persistKeyRE = new RegExp(`^${name}(?:V\\d+)?$`);
const store: { constructor: CR.Class; } | undefined = this.Webpack.find((exp: any) => {
// Find stores from exported instances
const { constructor } = exp;
return typeof constructor === "function" && (
constructor.displayName === name
|| persistKeyRE.test(constructor.persistKey)
);
});
if (store)
return getClassChanges(store.constructor, source);
}
export function autoFindClass(this: typeof Vencord, source: CR.ClassMembers) {
let bestMatch: CR.ClassChanges | undefined;
let lowestChangedCount = Infinity;
const checked = new WeakSet<CR.Class>();
this.Webpack.find((exps: any) => {
for (const name in exps) {
let constructor: CR.Class;
// Some getters throw errors
try {
// Find classes from exported constructors
if (isValidClass(exps[name]))
constructor = exps[name];
// Find classes from exported instances
else if (isValidClass(exps[name]?.constructor))
({ constructor } = exps[name]);
else
continue;
} catch {
continue;
}
if (!checked.has(constructor)) {
checked.add(constructor);
const changes = getClassChanges(constructor, source);
const { changedCount } = changes;
if (changedCount < lowestChangedCount) {
lowestChangedCount = changedCount;
bestMatch = changes;
}
}
}
return false;
}, { isIndirect: true });
return bestMatch;
}
export function isValidClass(constructor: unknown): constructor is CR.Class {
if (typeof constructor !== "function")
return false;
const { prototype } = constructor;
return typeof prototype === "object" && prototype !== null;
}
export function getClassChanges(
constructors: [CR.Class, ...CR.Class[]] | CR.Class,
source: CR.ClassMembers
): CR.ClassChanges {
if (!Array.isArray(constructors))
constructors = [constructors];
let hasConstructorDefinition = false;
const constructorKeys = new Set<PropertyKey>();
const constructorDescriptors = new Map<PropertyKey, PropertyDescriptor>();
const prototypeKeys = new Set<PropertyKey>();
const prototypeDescriptors = new Map<PropertyKey, PropertyDescriptor>();
const matchedFields = new Set<string>();
// Ignore constructor definitions without parameters
const constructorRE = /[{}]constructor\([^)]/;
const fieldRE = /(?<=[{}]constructor\(.+?{.+\(this,")[^"]+(?=",)/g;
for (const constructor of constructors) {
const constructorString = constructor.toString();
if (constructorRE.test(constructorString))
hasConstructorDefinition = true;
const constDescriptors = Object.getOwnPropertyDescriptors(constructor);
for (const key of Object.getOwnPropertyNames(constructor)) {
constructorKeys.add(key);
constructorDescriptors.set(key, constDescriptors[key]!);
}
for (const key of Object.getOwnPropertySymbols(constructor)) {
constructorKeys.add(key);
constructorDescriptors.set(key, constDescriptors[key]!);
}
const { prototype } = constructor;
const protoDescriptors = Object.getOwnPropertyDescriptors(prototype);
for (const key of Object.getOwnPropertyNames(prototype)) {
prototypeKeys.add(key);
prototypeDescriptors.set(key, protoDescriptors[key]!);
}
for (const key of Object.getOwnPropertySymbols(prototype)) {
prototypeKeys.add(key);
prototypeDescriptors.set(key, protoDescriptors[key]!);
}
for (const [field] of constructorString.matchAll(fieldRE))
matchedFields.add(field);
}
const additions: CR.ClassMembers = {
constructorDefinition: false,
staticMethodsAndFields: [],
staticGetters: [],
staticSetters: [],
methods: [],
getters: [],
setters: [],
fields: []
};
let unchangedCount = 0;
let changedCount = 0;
// Constructor definition with parameters removal
let constructorDefinition = false;
if (hasConstructorDefinition) {
if (source.constructorDefinition) {
unchangedCount++;
} else {
additions.constructorDefinition = true;
changedCount++;
}
} else if (source.constructorDefinition) {
constructorDefinition = true;
changedCount++;
} else {
unchangedCount++;
}
// Static member removals
const staticMethodsAndFields = new Set(source.staticMethodsAndFields);
const staticGetters = new Set(source.staticGetters);
const staticSetters = new Set(source.staticSetters);
const ignoredConstructorKeys = new Set<PropertyKey>(["length", "name", "prototype"]);
for (const rawKey of constructorKeys) {
if (ignoredConstructorKeys.has(rawKey)) continue;
const descriptor = constructorDescriptors.get(rawKey)!;
const key = rawKey.toString();
if (descriptor.get) {
if (staticGetters.has(key)) {
staticGetters.delete(key);
unchangedCount++;
} else {
additions.staticGetters.push(key);
changedCount++;
}
if (descriptor.set) {
if (staticSetters.has(key)) {
staticSetters.delete(key);
unchangedCount++;
} else {
additions.staticSetters.push(key);
changedCount++;
}
}
continue;
}
if (descriptor.set) {
if (staticSetters.has(key)) {
staticSetters.delete(key);
unchangedCount++;
} else {
additions.staticSetters.push(key);
changedCount++;
}
continue;
}
if (staticMethodsAndFields.has(key)) {
staticMethodsAndFields.delete(key);
unchangedCount++;
} else {
additions.staticMethodsAndFields.push(key);
changedCount++;
}
}
changedCount += staticMethodsAndFields.size + staticGetters.size + staticSetters.size;
// Instance method and accessor removals
const methods = new Set(source.methods);
const getters = new Set(source.getters);
const setters = new Set(source.setters);
const ignoredPrototypeKeys = new Set<PropertyKey>(["constructor"]);
for (const rawKey of prototypeKeys) {
if (ignoredPrototypeKeys.has(rawKey)) continue;
const descriptor = prototypeDescriptors.get(rawKey)!;
const key = rawKey.toString();
if (descriptor.get) {
if (getters.has(key)) {
getters.delete(key);
unchangedCount++;
} else {
additions.getters.push(key);
changedCount++;
}
if (descriptor.set) {
if (setters.has(key)) {
setters.delete(key);
unchangedCount++;
} else {
additions.setters.push(key);
changedCount++;
}
}
continue;
}
if (descriptor.set) {
if (setters.has(key)) {
setters.delete(key);
unchangedCount++;
} else {
additions.setters.push(key);
changedCount++;
}
continue;
}
if (methods.has(key)) {
methods.delete(key);
unchangedCount++;
} else {
additions.methods.push(key);
changedCount++;
}
}
changedCount += methods.size + getters.size + setters.size;
// Field removals
const fields = new Set(source.fields);
for (const field of matchedFields) {
if (fields.has(field)) {
fields.delete(field);
unchangedCount++;
} else {
additions.fields.push(field);
changedCount++;
}
}
changedCount += fields.size;
return {
additions,
removals: {
constructorDefinition,
staticMethodsAndFields: [...staticMethodsAndFields],
staticGetters: [...staticGetters],
staticSetters: [...staticSetters],
methods: [...methods],
getters: [...getters],
setters: [...setters],
fields: [...fields]
},
unchangedCount,
changedCount
};
}
export function autoFindEnum(this: typeof Vencord, source: CR.EnumSource) {
let bestMatch: CR.EnumChanges | undefined;
let lowestChangedCount = Infinity;
const checked = new WeakSet();
this.Webpack.find((exps: any) => {
for (const name in exps) {
let exp: unknown;
// Some getters throw errors
try {
exp = exps[name];
} catch {
continue;
}
if (isValidEnum(exp) && !checked.has(exp)) {
checked.add(exp);
const changes = getEnumChanges(exp, source);
const { changedCount } = changes;
if (changedCount < lowestChangedCount) {
lowestChangedCount = changedCount;
bestMatch = changes;
}
}
}
return false;
}, { isIndirect: true });
return bestMatch;
}
export function isValidEnum(obj: unknown): obj is CR.EnumMembers {
return typeof obj === "object"
&& obj !== null
&& !Array.isArray(obj);
}
export function getEnumChanges(obj: CR.EnumMembers, source: CR.EnumSource): CR.EnumChanges {
const additions: CR.EnumMembers = {};
const removals: CR.EnumMembers = { ...source };
let unchangedCount = 0;
let changedCount = 0;
for (const key in obj) {
// Ignore numeric enum reverse mapping
if (parseFloat(key) === Number(key)) continue;
// Some getters throw errors
try {
const value = obj[key]!;
if (key in source && value === source[key]) {
delete removals[key];
unchangedCount++;
} else {
additions[key] = value;
changedCount++;
}
} catch {
changedCount = Infinity;
break;
}
}
changedCount += Object.keys(removals).length;
return {
additions,
removals,
unchangedCount,
changedCount
};
}

View file

@ -13,8 +13,8 @@ import { satisfies, subset, valid, validRange } from "semver";
import type { JsonObject, JsonValue } from "type-fest";
import { config } from "./config.mjs";
import type { autoFindClass, autoFindEnum, autoFindStore } from "./finds.mts";
import type { CR } from "./types.mts";
import type { autoFindClass, autoFindEnum, autoFindStore } from "./utils.mts";
export async function getChangeReport(page: Page): Promise<CR.ChangeReport> {
const { rootDir, deps, src } = config;
@ -290,7 +290,7 @@ async function getClassReport(
changes.unchangedCount > 1
|| changes.unchangedCount > 0
&& (changes.additions.constructorDefinition
|| changes.removals.constructorDefinition)
|| changes.removals.constructorDefinition)
) {
checkClassIgnores(changes, config, report);
report.changes = changes;

View file

@ -9,12 +9,18 @@ import { join } from "path";
import puppeteer from "puppeteer-core";
import { validateEnv } from "../utils.mjs";
import { assertEnvValidity } from "../utils.mjs";
import { autoFindClass, autoFindEnum, autoFindStore, getClassChanges, getEnumChanges, isValidClass, isValidEnum } from "./finds.mjs";
import { getChangeReport } from "./getChangeReport.mjs";
import { logSummary } from "./logSummary.mjs";
import { autoFindClass, autoFindEnum, autoFindStore, getClassChanges, getEnumChanges, isValidClass, isValidEnum } from "./utils.mjs";
import { postError, postReport } from "./webhooks.mjs";
validateEnv(process.env, {
process.on("uncaughtExceptionMonitor", error => {
const { DISCORD_WEBHOOK, CHANNEL } = process.env;
postError(error, DISCORD_WEBHOOK, CHANNEL);
});
assertEnvValidity(process.env, {
CHANNEL: ["stable", "ptb", "canary"],
CHROMIUM_BIN: true,
DISCORD_TOKEN: true,
@ -69,6 +75,5 @@ browser.close();
logSummary(report, CHANNEL);
if (DISCORD_WEBHOOK) {
// TODO
}
if (DISCORD_WEBHOOK)
postReport(report, DISCORD_WEBHOOK, CHANNEL);

View file

@ -5,11 +5,12 @@
*/
import type { CR } from "./types.mts";
import { capitalize, codeBlock, formatChannel, formatEnumEntryList, formatKeyList, formatWarnList } from "./utils.mjs";
export function logSummary(report: CR.ChangeReport, channel: "stable" | "ptb" | "canary") {
export function logSummary(report: CR.ChangeReport, channel?: string | undefined) {
const { deps, src } = report;
let summary = `# Change Report (${channel === "ptb" ? channel.toUpperCase() : capitalize(channel)})\n`;
let summary = `# Change Report (${formatChannel(channel)})\n`;
let sections = "";
@ -77,12 +78,12 @@ export function logSummary(report: CR.ChangeReport, channel: "stable" | "ptb" |
section += `* The report for \`${name}\` has ${warns.length} warning${warns.length === 1 ? "" : "s"}:\n`
+ formatWarnList(warns);
section += `* The report for \`${name}\` has an error:\n` + formatError(error);
section += `* The report for \`${name}\` has an error:\n` + codeBlock(error);
}
} else
section += ". \n";
} else
section += `\`${fileName}\` has a file-level error:\n` + formatError(fileError);
section += `\`${fileName}\` has a file-level error:\n` + codeBlock(fileError);
}
if (fileToLogCount > 0) {
@ -252,12 +253,12 @@ export function logSummary(report: CR.ChangeReport, channel: "stable" | "ptb" |
section += `* The report for ${type} \`${identifier}\` has ${warns.length} warning${warns.length === 1 ? "" : "s"}:\n`
+ formatWarnList(warns);
section += `* The report for ${type} \`${identifier}\` has an error:\n${formatError(error)}`;
section += `* The report for ${type} \`${identifier}\` has an error:\n` + codeBlock(error);
}
} else
section += ". \n";
} else
section += `\`${fileName}\` has a file-level error:\n${formatError(fileError)}`;
section += `\`${fileName}\` has a file-level error:\n` + codeBlock(fileError);
}
if (fileToLogCount > 0) {
@ -268,29 +269,7 @@ export function logSummary(report: CR.ChangeReport, channel: "stable" | "ptb" |
sections += "### All watched declarations are unchanged without warnings.\n";
}
summary += sections || "## There are 0 watched dependencies and declarations.";
summary += sections || "## There are 0 watched dependencies and declarations.\n";
console.log(summary);
}
function capitalize(string: string) {
return string.replace(/^./, c => c.toUpperCase());
}
function formatWarnList(warns: string[]) {
return warns.map(formatError).join("");
}
function formatError(error: string) {
return `\`\`\`\n${error}\n\`\`\`\n`;
}
function formatKeyList(keys: string[], indentLevel = 0) {
const indent = " ".repeat(indentLevel);
return keys.map(key => indent + `* \`${key}\`\n`).join("");
}
function formatEnumEntryList(entries: [key: string, value: unknown][], indentLevel = 0) {
const indent = " ".repeat(indentLevel);
return entries.map(([key, value]) => indent + `* \`${key} = ${JSON.stringify(value)}\`\n`).join("");
}

View file

@ -4,369 +4,43 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
// eslint-disable-next-line import/no-relative-packages
import type * as Vencord from "../../../../src/Vencord.ts";
import type { CR } from "./types.mts";
export function autoFindStore(this: typeof Vencord, name: string, source: CR.ClassMembers) {
const persistKeyRE = new RegExp(`^${name}(?:V\\d+)?$`);
const store: { constructor: CR.Class; } | undefined = this.Webpack.find((exp: any) => {
// Find stores from exported instances
const { constructor } = exp;
return typeof constructor === "function" && (
constructor.displayName === name
|| persistKeyRE.test(constructor.persistKey)
);
});
if (store)
return getClassChanges(store.constructor, source);
export function capitalize(string: string) {
return string.replace(/^./, c => c.toUpperCase());
}
export function autoFindClass(this: typeof Vencord, source: CR.ClassMembers) {
let bestMatch: CR.ClassChanges | undefined;
let lowestChangedCount = Infinity;
const checked = new WeakSet<CR.Class>();
this.Webpack.find((exps: any) => {
for (const name in exps) {
let constructor: CR.Class;
// Some getters throw errors
try {
// Find classes from exported constructors
if (isValidClass(exps[name]))
constructor = exps[name];
// Find classes from exported instances
else if (isValidClass(exps[name]?.constructor))
({ constructor } = exps[name]);
else
continue;
} catch {
continue;
}
if (!checked.has(constructor)) {
checked.add(constructor);
const changes = getClassChanges(constructor, source);
const { changedCount } = changes;
if (changedCount < lowestChangedCount) {
lowestChangedCount = changedCount;
bestMatch = changes;
}
}
}
return false;
}, { isIndirect: true });
return bestMatch;
export function codeBlock(content: unknown) {
return `\`\`\`\n${content}\n\`\`\`\n`;
}
export function isValidClass(constructor: unknown): constructor is CR.Class {
if (typeof constructor !== "function")
return false;
const { prototype } = constructor;
return typeof prototype === "object" && prototype !== null;
}
export function getClassChanges(
constructors: [CR.Class, ...CR.Class[]] | CR.Class,
source: CR.ClassMembers
): CR.ClassChanges {
if (!Array.isArray(constructors))
constructors = [constructors];
let hasConstructorDefinition = false;
const constructorKeys = new Set<PropertyKey>();
const constructorDescriptors = new Map<PropertyKey, PropertyDescriptor>();
const prototypeKeys = new Set<PropertyKey>();
const prototypeDescriptors = new Map<PropertyKey, PropertyDescriptor>();
const matchedFields = new Set<string>();
// Ignore constructor definitions without parameters
const constructorRE = /[{}]constructor\([^)]/;
const fieldRE = /(?<=[{}]constructor\(.+?{.+\(this,")[^"]+(?=",)/g;
for (const constructor of constructors) {
const constructorString = constructor.toString();
if (constructorRE.test(constructorString))
hasConstructorDefinition = true;
const constDescriptors = Object.getOwnPropertyDescriptors(constructor);
for (const key of Object.getOwnPropertyNames(constructor)) {
constructorKeys.add(key);
constructorDescriptors.set(key, constDescriptors[key]!);
}
for (const key of Object.getOwnPropertySymbols(constructor)) {
constructorKeys.add(key);
constructorDescriptors.set(key, constDescriptors[key]!);
}
const { prototype } = constructor;
const protoDescriptors = Object.getOwnPropertyDescriptors(prototype);
for (const key of Object.getOwnPropertyNames(prototype)) {
prototypeKeys.add(key);
prototypeDescriptors.set(key, protoDescriptors[key]!);
}
for (const key of Object.getOwnPropertySymbols(prototype)) {
prototypeKeys.add(key);
prototypeDescriptors.set(key, protoDescriptors[key]!);
}
for (const [field] of constructorString.matchAll(fieldRE))
matchedFields.add(field);
export function formatChannel(channel?: string | undefined) {
switch (channel) {
case "stable":
case "canary":
return capitalize(channel);
case "ptb":
return channel.toUpperCase();
default:
return "Unknown";
}
const additions: CR.ClassMembers = {
constructorDefinition: false,
staticMethodsAndFields: [],
staticGetters: [],
staticSetters: [],
methods: [],
getters: [],
setters: [],
fields: []
};
let unchangedCount = 0;
let changedCount = 0;
// Constructor definition with parameters removal
let constructorDefinition = false;
if (hasConstructorDefinition) {
if (source.constructorDefinition) {
unchangedCount++;
} else {
additions.constructorDefinition = true;
changedCount++;
}
} else if (source.constructorDefinition) {
constructorDefinition = true;
changedCount++;
} else {
unchangedCount++;
}
// Static member removals
const staticMethodsAndFields = new Set(source.staticMethodsAndFields);
const staticGetters = new Set(source.staticGetters);
const staticSetters = new Set(source.staticSetters);
const ignoredConstructorKeys = new Set<PropertyKey>(["length", "name", "prototype"]);
for (const rawKey of constructorKeys) {
if (ignoredConstructorKeys.has(rawKey)) continue;
const descriptor = constructorDescriptors.get(rawKey)!;
const key = rawKey.toString();
if (descriptor.get) {
if (staticGetters.has(key)) {
staticGetters.delete(key);
unchangedCount++;
} else {
additions.staticGetters.push(key);
changedCount++;
}
if (descriptor.set) {
if (staticSetters.has(key)) {
staticSetters.delete(key);
unchangedCount++;
} else {
additions.staticSetters.push(key);
changedCount++;
}
}
continue;
}
if (descriptor.set) {
if (staticSetters.has(key)) {
staticSetters.delete(key);
unchangedCount++;
} else {
additions.staticSetters.push(key);
changedCount++;
}
continue;
}
if (staticMethodsAndFields.has(key)) {
staticMethodsAndFields.delete(key);
unchangedCount++;
} else {
additions.staticMethodsAndFields.push(key);
changedCount++;
}
}
changedCount += staticMethodsAndFields.size + staticGetters.size + staticSetters.size;
// Instance method and accessor removals
const methods = new Set(source.methods);
const getters = new Set(source.getters);
const setters = new Set(source.setters);
const ignoredPrototypeKeys = new Set<PropertyKey>(["constructor"]);
for (const rawKey of prototypeKeys) {
if (ignoredPrototypeKeys.has(rawKey)) continue;
const descriptor = prototypeDescriptors.get(rawKey)!;
const key = rawKey.toString();
if (descriptor.get) {
if (getters.has(key)) {
getters.delete(key);
unchangedCount++;
} else {
additions.getters.push(key);
changedCount++;
}
if (descriptor.set) {
if (setters.has(key)) {
setters.delete(key);
unchangedCount++;
} else {
additions.setters.push(key);
changedCount++;
}
}
continue;
}
if (descriptor.set) {
if (setters.has(key)) {
setters.delete(key);
unchangedCount++;
} else {
additions.setters.push(key);
changedCount++;
}
continue;
}
if (methods.has(key)) {
methods.delete(key);
unchangedCount++;
} else {
additions.methods.push(key);
changedCount++;
}
}
changedCount += methods.size + getters.size + setters.size;
// Field removals
const fields = new Set(source.fields);
for (const field of matchedFields) {
if (fields.has(field)) {
fields.delete(field);
unchangedCount++;
} else {
additions.fields.push(field);
changedCount++;
}
}
changedCount += fields.size;
return {
additions,
removals: {
constructorDefinition,
staticMethodsAndFields: [...staticMethodsAndFields],
staticGetters: [...staticGetters],
staticSetters: [...staticSetters],
methods: [...methods],
getters: [...getters],
setters: [...setters],
fields: [...fields]
},
unchangedCount,
changedCount
};
}
export function autoFindEnum(this: typeof Vencord, source: CR.EnumSource) {
let bestMatch: CR.EnumChanges | undefined;
let lowestChangedCount = Infinity;
const checked = new WeakSet();
this.Webpack.find((exps: any) => {
for (const name in exps) {
let exp: unknown;
// Some getters throw errors
try {
exp = exps[name];
} catch {
continue;
}
if (isValidEnum(exp) && !checked.has(exp)) {
checked.add(exp);
const changes = getEnumChanges(exp, source);
const { changedCount } = changes;
if (changedCount < lowestChangedCount) {
lowestChangedCount = changedCount;
bestMatch = changes;
}
}
}
return false;
}, { isIndirect: true });
return bestMatch;
export function formatWarnList(warns: string[]) {
return warns.map(codeBlock).join("");
}
export function isValidEnum(obj: unknown): obj is CR.EnumMembers {
return typeof obj === "object"
&& obj !== null
&& !Array.isArray(obj);
export function formatKeyList(keys: string[], indentLevel = 0) {
const indent = " ".repeat(indentLevel);
return keys.map(key => indent + `* \`${key}\`\n`).join("");
}
export function getEnumChanges(obj: CR.EnumMembers, source: CR.EnumSource): CR.EnumChanges {
const additions: CR.EnumMembers = {};
const removals: CR.EnumMembers = { ...source };
let unchangedCount = 0;
let changedCount = 0;
for (const key in obj) {
// Ignore numeric enum reverse mapping
if (parseFloat(key) === Number(key)) continue;
// Some getters throw errors
try {
const value = obj[key]!;
if (key in source && value === source[key]) {
delete removals[key];
unchangedCount++;
} else {
additions[key] = value;
changedCount++;
}
} catch {
changedCount = Infinity;
break;
}
}
changedCount += Object.keys(removals).length;
return {
additions,
removals,
unchangedCount,
changedCount
};
export function formatEnumEntryList(entries: [key: string, value: unknown][], indentLevel = 0) {
const indent = " ".repeat(indentLevel);
return entries.map(([key, value]) => indent + `* \`${key} = ${JSON.stringify(value)}\`\n`).join("");
}
export function getSummaryURL(channel?: string | undefined) {
const { GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_RUN_ID, GITHUB_RUN_ATTEMPT } = process.env;
if (GITHUB_SERVER_URL && GITHUB_REPOSITORY && GITHUB_RUN_ID && GITHUB_RUN_ATTEMPT)
return `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/attempts/${GITHUB_RUN_ATTEMPT}`
+ `#:~:text=Change%20Report%20%28${formatChannel(channel)}%29`;
}

View file

@ -0,0 +1,117 @@
/*
* discord-types
* Copyright (C) 2024 Vencord project contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import type { CR } from "./types.mts";
import { codeBlock, formatChannel, getSummaryURL } from "./utils.mjs";
export async function postError(
error: Error,
webhookURL: string | undefined,
channel?: string | undefined
) {
if (!webhookURL) return;
const res = await fetch(webhookURL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
username: "Change Reporter",
embeds: [{
title: `Change Report (${formatChannel(channel)})`,
description: "### Fatal error:\n" + codeBlock(error.stack),
url: getSummaryURL(channel),
color: 0xF23F42
}]
})
});
if (!res.ok)
console.error(`Failed to exectute webhook (status '${res.status} ${res.statusText}').`);
}
export async function postReport(
report: CR.ChangeReport,
webhookURL: string,
channel?: string | undefined
) {
const { deps, src } = report;
let areChanges = false;
let description = "";
if (deps.length > 0) {
let passedCount = 0;
let warnedCount = 0;
let failedCount = 0;
let erroredCount = 0;
for (const report of deps) {
passedCount += report.passed.length;
warnedCount += report.warned.length;
failedCount += report.failed.length;
erroredCount += report.errored.length;
}
const toLogCount = warnedCount + failedCount + erroredCount;
const count = passedCount + toLogCount;
if (count > 0) {
description += "### Dependencies:\n";
if (toLogCount > 0) {
areChanges = true;
description += `${count} watched dependenc${count === 1 ? "y" : "ies"} in ${deps.length} file${deps.length === 1 ? "" : "s"}:\n`
+ `* ${passedCount} passed without warnings.\n`
+ `* ${warnedCount} passed with warnings.\n`
+ `* ${failedCount} failed.\n`
+ `* ${erroredCount} errored.\n`;
} else
description += "All watched dependencies passed without warnings.\n";
}
}
if (src.length > 0) {
let unchangedCount = 0;
let warnedCount = 0;
let changedCount = 0;
let erroredCount = 0;
for (const report of src) {
unchangedCount += report.unchanged.length;
warnedCount += report.warned.length;
changedCount += report.changed.length;
erroredCount += report.errored.length;
}
const toLogCount = warnedCount + changedCount + erroredCount;
const count = unchangedCount + toLogCount;
if (count > 0) {
description += "### Declarations:\n";
if (toLogCount > 0) {
areChanges = true;
description += `${count} watched declaration${count === 1 ? "" : "s"} in ${src.length} file${src.length === 1 ? "" : "s"}:\n`
+ `* ${unchangedCount} ${unchangedCount === 1 ? "is" : "are"} unchanged without warnings.\n`
+ `* ${warnedCount} ${warnedCount === 1 ? "is" : "are"} unchanged with warnings.\n`
+ `* ${changedCount} ha${changedCount === 1 ? "s" : "ve"} changes.\n`
+ `* ${erroredCount} errored.\n`;
} else
description += "All watched declarations are unchanged without warnings.\n";
}
}
description ||= "### There are 0 watched dependencies and declarations.\n";
const res = await fetch(webhookURL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
username: "Change Reporter",
embeds: [{
title: `Change Report (${formatChannel(channel)})`,
description,
url: getSummaryURL(channel),
color: areChanges ? 0xF0B132 : 0x23A559
}]
})
});
if (!res.ok)
console.error(`Failed to exectute webhook (status '${res.status} ${res.statusText}').`);
}

View file

@ -12,7 +12,7 @@ type ValidEnv<Config extends EnvConfig> = NodeJS.ProcessEnv & {
: string;
} & { [Key in keyof Config as false extends Config[Key] ? Key : never]?: string; };
export function validateEnv<const Config extends EnvConfig>(
export function assertEnvValidity<const Config extends EnvConfig>(
env: NodeJS.ProcessEnv,
config: Config
): asserts env is ValidEnv<Config> {

View file

@ -80,7 +80,7 @@ export enum CodedLinkType {
TEMPLATE = "TEMPLATE",
}
export type MessageComponent = MessageActionRowComponent | MessageButtonComponent | MessageSelectComponent | MessageTextInputComponent | MessageTextComponent | MessageMediaGalleryComponent | MessageSeparatorComponent;
export type MessageComponent = MessageActionRowComponent | MessageButtonComponent | MessageSelectComponent | MessageTextInputComponent | MessageTextComponent | MessageMediaGalleryComponent | MessageSeparatorComponent | MessageContentInventoryEntryComponent;
export interface MessageComponentBase {
id: string;

View file

@ -69,11 +69,11 @@ importers:
specifier: ^2.4.5
version: 2.4.5
'@typescript-eslint/eslint-plugin':
specifier: ^7.15.0
version: 7.15.0(@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
specifier: ^7.16.0
version: 7.16.0(@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
'@typescript-eslint/parser':
specifier: ^7.15.0
version: 7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
specifier: ^7.16.0
version: 7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
'@vencord/discord-types':
specifier: workspace:^
version: link:packages/discord-types
@ -91,7 +91,7 @@ importers:
version: 8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)
eslint-import-resolver-alias:
specifier: ^1.1.2
version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)))
version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)))
eslint-plugin-path-alias:
specifier: ^2.1.0
version: 2.1.0(patch_hash=japuwsqfkulviwgkm4kd2oi3ky)(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))
@ -100,7 +100,7 @@ importers:
version: 12.1.1(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))
eslint-plugin-unused-imports:
specifier: ^3.2.0
version: 3.2.0(@typescript-eslint/eslint-plugin@7.15.0(@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))
version: 3.2.0(@typescript-eslint/eslint-plugin@7.16.0(@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))
highlight.js:
specifier: 11.8.0
version: 11.8.0
@ -178,8 +178,8 @@ importers:
specifier: ^7.5.8
version: 7.5.8
'@typescript-eslint/typescript-estree':
specifier: ^8.0.0-alpha.39
version: 8.0.0-alpha.40(typescript@5.5.3)
specifier: ^8.0.0-alpha.41
version: 8.0.0-alpha.41(typescript@5.5.3)
eslint:
specifier: ^9.6.0
version: 9.6.0
@ -200,7 +200,7 @@ importers:
version: 54.0.0(eslint@9.6.0)
eslint-plugin-unused-imports:
specifier: ^4.0.0
version: 4.0.0(@typescript-eslint/eslint-plugin@7.15.0(@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@9.6.0)
version: 4.0.0(@typescript-eslint/eslint-plugin@7.16.0(@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@9.6.0)
puppeteer-core:
specifier: ^22.12.1
version: 22.12.1
@ -214,8 +214,8 @@ importers:
specifier: ^5.5.3
version: 5.5.3
typescript-eslint:
specifier: ^8.0.0-alpha.39
version: 8.0.0-alpha.39(eslint@9.6.0)(typescript@5.5.3)
specifier: ^8.0.0-alpha.41
version: 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3)
packages/vencord-types:
dependencies:
@ -777,8 +777,8 @@ packages:
'@types/yazl@2.4.5':
resolution: {integrity: sha512-qpmPfx32HS7vlGJf7EsoM9qJnLZhXJBf1KH0hzfdc+D794rljQWh4H0I/UrZy+6Nhqn0l2jdBZXBGZtR1vnHqw==}
'@typescript-eslint/eslint-plugin@7.15.0':
resolution: {integrity: sha512-uiNHpyjZtFrLwLDpHnzaDlP3Tt6sGMqTCiqmxaN4n4RP0EfYZDODJyddiFDF44Hjwxr5xAcaYxVKm9QKQFJFLA==}
'@typescript-eslint/eslint-plugin@7.16.0':
resolution: {integrity: sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
'@typescript-eslint/parser': ^7.0.0
@ -788,8 +788,8 @@ packages:
typescript:
optional: true
'@typescript-eslint/eslint-plugin@8.0.0-alpha.39':
resolution: {integrity: sha512-ILv1vDA8M9ah1vzYpnOs4UOLRdB63Ki/rsxedVikjMLq68hFfpsDR25bdMZ4RyUkzLJwOhcg3Jujm/C1nupXKA==}
'@typescript-eslint/eslint-plugin@8.0.0-alpha.41':
resolution: {integrity: sha512-WePtbzWMaQO4qtGAXp3zzEN8yYZCEuAHVCERCUXgoSUTQ80F5UB7T5lYyA9ySpFDB7rqJ2ev98DtnbS4U3Ms+w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
@ -799,8 +799,8 @@ packages:
typescript:
optional: true
'@typescript-eslint/parser@7.15.0':
resolution: {integrity: sha512-k9fYuQNnypLFcqORNClRykkGOMOj+pV6V91R4GO/l1FDGwpqmSwoOQrOHo3cGaH63e+D3ZiCAOsuS/D2c99j/A==}
'@typescript-eslint/parser@7.16.0':
resolution: {integrity: sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
eslint: ^8.56.0
@ -809,8 +809,8 @@ packages:
typescript:
optional: true
'@typescript-eslint/parser@8.0.0-alpha.39':
resolution: {integrity: sha512-5k+pwV91plJojHgZkWlq4/TQdOrnEaeSvt48V0m8iEwdMJqX/63BXYxy8BUOSghWcjp05s73vy9HJjovAKmHkQ==}
'@typescript-eslint/parser@8.0.0-alpha.41':
resolution: {integrity: sha512-7HMXwy/q/59ZASBXz2FtdIsR7LgABrR8j2dTKq9GMR8OkjjdO4klxWSY/uOBozVt4UxlMRYsBdBDhEq4/tHRiw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@ -823,16 +823,16 @@ packages:
resolution: {integrity: sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==}
engines: {node: ^18.18.0 || >=20.0.0}
'@typescript-eslint/scope-manager@7.15.0':
resolution: {integrity: sha512-Q/1yrF/XbxOTvttNVPihxh1b9fxamjEoz2Os/Pe38OHwxC24CyCqXxGTOdpb4lt6HYtqw9HetA/Rf6gDGaMPlw==}
'@typescript-eslint/scope-manager@7.16.0':
resolution: {integrity: sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==}
engines: {node: ^18.18.0 || >=20.0.0}
'@typescript-eslint/scope-manager@8.0.0-alpha.39':
resolution: {integrity: sha512-HCBlKQROY+JIgWolucdFMj1W3VUnnIQTdxAhxJTAj3ix2nASmvKIFgrdo5KQMrXxQj6tC4l3zva10L+s0dUIIw==}
'@typescript-eslint/scope-manager@8.0.0-alpha.41':
resolution: {integrity: sha512-iNxuQ0TMVfFiMJ2al4bGd/mY9+aLtBxnHfo7B2xoVzR6cRFgUdBLlMa//MSIjSmVRpCEqNLQnkxpJb96tFG+xw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/type-utils@7.15.0':
resolution: {integrity: sha512-SkgriaeV6PDvpA6253PDVep0qCqgbO1IOBiycjnXsszNTVQe5flN5wR5jiczoEoDEnAqYFSFFc9al9BSGVltkg==}
'@typescript-eslint/type-utils@7.16.0':
resolution: {integrity: sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
eslint: ^8.56.0
@ -841,8 +841,8 @@ packages:
typescript:
optional: true
'@typescript-eslint/type-utils@8.0.0-alpha.39':
resolution: {integrity: sha512-alO13fRU6yVeJbwl9ESI3AYhq5dQdz3Dpd0I5B4uezs2lvgYp44dZsj5hWyPz/kL7JFEsjbn+4b/CZA0OQJzjA==}
'@typescript-eslint/type-utils@8.0.0-alpha.41':
resolution: {integrity: sha512-+QIA1z/jrox6bbvqlyqBQjotpevieLTycfiuoKuqGcKoskFZV5Rma51BV8LCJacnOafwJtSi+7b8zDo8OsXUvA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '*'
@ -854,16 +854,12 @@ packages:
resolution: {integrity: sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==}
engines: {node: ^18.18.0 || >=20.0.0}
'@typescript-eslint/types@7.15.0':
resolution: {integrity: sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==}
'@typescript-eslint/types@7.16.0':
resolution: {integrity: sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==}
engines: {node: ^18.18.0 || >=20.0.0}
'@typescript-eslint/types@8.0.0-alpha.39':
resolution: {integrity: sha512-yINN7j0/+S1VGSp0IgH52oQvUx49vkOug6xbrDA/9o+U55yCAQKSvYWvzYjNa+SZE3hXI0zwvYtMVsIAAMmKIQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/types@8.0.0-alpha.40':
resolution: {integrity: sha512-44mUq4VZVydxNlOM8Xtp/BXDkyfuvvjgPIBf7vRQDutrLDeNS0pJ9pcSloSbop5MwKLfJjBU+PbwnJPQM+DWNg==}
'@typescript-eslint/types@8.0.0-alpha.41':
resolution: {integrity: sha512-n0P2FP3YC3pD3yoiCf4lHqbUP45xlnOk8HkjB+LtKSUZZWLLJ8k1ZXZtQj7MEX22tytCMj//Bmq403xFuCwfIg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@7.14.1':
@ -875,8 +871,8 @@ packages:
typescript:
optional: true
'@typescript-eslint/typescript-estree@7.15.0':
resolution: {integrity: sha512-gjyB/rHAopL/XxfmYThQbXbzRMGhZzGw6KpcMbfe8Q3nNQKStpxnUKeXb0KiN/fFDR42Z43szs6rY7eHk0zdGQ==}
'@typescript-eslint/typescript-estree@7.16.0':
resolution: {integrity: sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
typescript: '*'
@ -884,17 +880,8 @@ packages:
typescript:
optional: true
'@typescript-eslint/typescript-estree@8.0.0-alpha.39':
resolution: {integrity: sha512-S8gREuP8r8PCxGegeojeXntx0P50ul9YH7c7JYpbLIIsEPNr5f7UHlm+I1NUbL04CBin4kvZ60TG4eWr/KKN9A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
'@typescript-eslint/typescript-estree@8.0.0-alpha.40':
resolution: {integrity: sha512-bz1rX5GXvGdx686FghDxPqGwgntlseZCQSRrVGDDOZlLSoWJnbfkzxXGOWch9c3ttcGkdFy/DiCyKKga3hrq0g==}
'@typescript-eslint/typescript-estree@8.0.0-alpha.41':
resolution: {integrity: sha512-adCr+vbLYTFhwhIwjIjjMxTdUYiPA2Jlyuhnbj092IzgLHtT79bvuwcgPWeTyLbFb/13SMKmOEka00xHiqLpig==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '*'
@ -908,14 +895,14 @@ packages:
peerDependencies:
eslint: ^8.56.0
'@typescript-eslint/utils@7.15.0':
resolution: {integrity: sha512-hfDMDqaqOqsUVGiEPSMLR/AjTSCsmJwjpKkYQRo1FNbmW4tBwBspYDwO9eh7sKSTwMQgBw9/T4DHudPaqshRWA==}
'@typescript-eslint/utils@7.16.0':
resolution: {integrity: sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
eslint: ^8.56.0
'@typescript-eslint/utils@8.0.0-alpha.39':
resolution: {integrity: sha512-Nr2PrlfNhrNQTlFHlD7XJdTGw/Vt8qY44irk6bfjn9LxGdSG5e4c1R2UN6kvGMhhx20DBPbM7q3Z3r+huzmL1w==}
'@typescript-eslint/utils@8.0.0-alpha.41':
resolution: {integrity: sha512-DTxc9VdERS6iloiw1P5tgRDqRArmp/sIuvgdHBvGh2SiltEFc3VjLGnHHGSTr6GfH7tjFWvcCnCtxx+pjWfp5Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@ -924,16 +911,12 @@ packages:
resolution: {integrity: sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==}
engines: {node: ^18.18.0 || >=20.0.0}
'@typescript-eslint/visitor-keys@7.15.0':
resolution: {integrity: sha512-Hqgy/ETgpt2L5xueA/zHHIl4fJI2O4XUE9l4+OIfbJIRSnTJb/QscncdqqZzofQegIJugRIF57OJea1khw2SDw==}
'@typescript-eslint/visitor-keys@7.16.0':
resolution: {integrity: sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==}
engines: {node: ^18.18.0 || >=20.0.0}
'@typescript-eslint/visitor-keys@8.0.0-alpha.39':
resolution: {integrity: sha512-DVJ0UdhucZy+/1GlIy7FX2+CFhCeNAi4VwaEAe7u2UDenQr9/kGqvzx00UlpWibmEVDw4KsPOI7Aqa1+2Vqfmw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/visitor-keys@8.0.0-alpha.40':
resolution: {integrity: sha512-y1stojSPb5D3M8VlGGpaiBU5XxGLe+sPuW0YbLe09Lxvo4AwKGvhAr5lhqJZo4z6qHNz385+6+BS63+qIQdYLw==}
'@typescript-eslint/visitor-keys@8.0.0-alpha.41':
resolution: {integrity: sha512-uetCAUBVC+YarBdZnWzDDgX11PpAEGV8Cw31I3d1xNrhx6/bJGThKX+holEmd3amMdnr4w/XUKH/4YuQOgtjDA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@ungap/structured-clone@1.2.0':
@ -2918,8 +2901,8 @@ packages:
resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==}
engines: {node: '>= 0.4'}
typescript-eslint@8.0.0-alpha.39:
resolution: {integrity: sha512-bsuR1BVJfHr7sBh7Cca962VPIcP+5UWaIa/+6PpnFZ+qtASjGTxKWIF5dG2o73BX9NsyqQfvRWujb3M9CIoRXA==}
typescript-eslint@8.0.0-alpha.41:
resolution: {integrity: sha512-+e7D2XDZeHLe9D3bP7S0Va8YdLHzn3YcesoxMS9SjMWhtaSb5ylxk2txqT84sUS0WIDQetZlvDg2/UmY5B/ycg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '*'
@ -3484,14 +3467,14 @@ snapshots:
dependencies:
'@types/node': 18.19.39
'@typescript-eslint/eslint-plugin@7.15.0(@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)':
'@typescript-eslint/eslint-plugin@7.16.0(@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)':
dependencies:
'@eslint-community/regexpp': 4.10.0
'@typescript-eslint/parser': 7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
'@typescript-eslint/scope-manager': 7.15.0
'@typescript-eslint/type-utils': 7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
'@typescript-eslint/utils': 7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
'@typescript-eslint/visitor-keys': 7.15.0
'@typescript-eslint/parser': 7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
'@typescript-eslint/scope-manager': 7.16.0
'@typescript-eslint/type-utils': 7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
'@typescript-eslint/utils': 7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
'@typescript-eslint/visitor-keys': 7.16.0
eslint: 8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)
graphemer: 1.4.0
ignore: 5.3.1
@ -3502,14 +3485,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/eslint-plugin@8.0.0-alpha.39(@typescript-eslint/parser@8.0.0-alpha.39(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0)(typescript@5.5.3)':
'@typescript-eslint/eslint-plugin@8.0.0-alpha.41(@typescript-eslint/parser@8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0)(typescript@5.5.3)':
dependencies:
'@eslint-community/regexpp': 4.10.0
'@typescript-eslint/parser': 8.0.0-alpha.39(eslint@9.6.0)(typescript@5.5.3)
'@typescript-eslint/scope-manager': 8.0.0-alpha.39
'@typescript-eslint/type-utils': 8.0.0-alpha.39(eslint@9.6.0)(typescript@5.5.3)
'@typescript-eslint/utils': 8.0.0-alpha.39(eslint@9.6.0)(typescript@5.5.3)
'@typescript-eslint/visitor-keys': 8.0.0-alpha.39
'@typescript-eslint/parser': 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3)
'@typescript-eslint/scope-manager': 8.0.0-alpha.41
'@typescript-eslint/type-utils': 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3)
'@typescript-eslint/utils': 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3)
'@typescript-eslint/visitor-keys': 8.0.0-alpha.41
eslint: 9.6.0
graphemer: 1.4.0
ignore: 5.3.1
@ -3520,12 +3503,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)':
'@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)':
dependencies:
'@typescript-eslint/scope-manager': 7.15.0
'@typescript-eslint/types': 7.15.0
'@typescript-eslint/typescript-estree': 7.15.0(typescript@5.5.3)
'@typescript-eslint/visitor-keys': 7.15.0
'@typescript-eslint/scope-manager': 7.16.0
'@typescript-eslint/types': 7.16.0
'@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.3)
'@typescript-eslint/visitor-keys': 7.16.0
debug: 4.3.5
eslint: 8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)
optionalDependencies:
@ -3533,12 +3516,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.0.0-alpha.39(eslint@9.6.0)(typescript@5.5.3)':
'@typescript-eslint/parser@8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.0.0-alpha.39
'@typescript-eslint/types': 8.0.0-alpha.39
'@typescript-eslint/typescript-estree': 8.0.0-alpha.39(typescript@5.5.3)
'@typescript-eslint/visitor-keys': 8.0.0-alpha.39
'@typescript-eslint/scope-manager': 8.0.0-alpha.41
'@typescript-eslint/types': 8.0.0-alpha.41
'@typescript-eslint/typescript-estree': 8.0.0-alpha.41(typescript@5.5.3)
'@typescript-eslint/visitor-keys': 8.0.0-alpha.41
debug: 4.3.5
eslint: 9.6.0
optionalDependencies:
@ -3551,20 +3534,20 @@ snapshots:
'@typescript-eslint/types': 7.14.1
'@typescript-eslint/visitor-keys': 7.14.1
'@typescript-eslint/scope-manager@7.15.0':
'@typescript-eslint/scope-manager@7.16.0':
dependencies:
'@typescript-eslint/types': 7.15.0
'@typescript-eslint/visitor-keys': 7.15.0
'@typescript-eslint/types': 7.16.0
'@typescript-eslint/visitor-keys': 7.16.0
'@typescript-eslint/scope-manager@8.0.0-alpha.39':
'@typescript-eslint/scope-manager@8.0.0-alpha.41':
dependencies:
'@typescript-eslint/types': 8.0.0-alpha.39
'@typescript-eslint/visitor-keys': 8.0.0-alpha.39
'@typescript-eslint/types': 8.0.0-alpha.41
'@typescript-eslint/visitor-keys': 8.0.0-alpha.41
'@typescript-eslint/type-utils@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)':
'@typescript-eslint/type-utils@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)':
dependencies:
'@typescript-eslint/typescript-estree': 7.15.0(typescript@5.5.3)
'@typescript-eslint/utils': 7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
'@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.3)
'@typescript-eslint/utils': 7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
debug: 4.3.5
eslint: 8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)
ts-api-utils: 1.3.0(typescript@5.5.3)
@ -3573,10 +3556,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/type-utils@8.0.0-alpha.39(eslint@9.6.0)(typescript@5.5.3)':
'@typescript-eslint/type-utils@8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3)':
dependencies:
'@typescript-eslint/typescript-estree': 8.0.0-alpha.39(typescript@5.5.3)
'@typescript-eslint/utils': 8.0.0-alpha.39(eslint@9.6.0)(typescript@5.5.3)
'@typescript-eslint/typescript-estree': 8.0.0-alpha.41(typescript@5.5.3)
'@typescript-eslint/utils': 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3)
debug: 4.3.5
ts-api-utils: 1.3.0(typescript@5.5.3)
optionalDependencies:
@ -3587,11 +3570,9 @@ snapshots:
'@typescript-eslint/types@7.14.1': {}
'@typescript-eslint/types@7.15.0': {}
'@typescript-eslint/types@7.16.0': {}
'@typescript-eslint/types@8.0.0-alpha.39': {}
'@typescript-eslint/types@8.0.0-alpha.40': {}
'@typescript-eslint/types@8.0.0-alpha.41': {}
'@typescript-eslint/typescript-estree@7.14.1(typescript@5.5.3)':
dependencies:
@ -3608,10 +3589,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/typescript-estree@7.15.0(typescript@5.5.3)':
'@typescript-eslint/typescript-estree@7.16.0(typescript@5.5.3)':
dependencies:
'@typescript-eslint/types': 7.15.0
'@typescript-eslint/visitor-keys': 7.15.0
'@typescript-eslint/types': 7.16.0
'@typescript-eslint/visitor-keys': 7.16.0
debug: 4.3.5
globby: 11.1.0
is-glob: 4.0.3
@ -3623,25 +3604,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/typescript-estree@8.0.0-alpha.39(typescript@5.5.3)':
'@typescript-eslint/typescript-estree@8.0.0-alpha.41(typescript@5.5.3)':
dependencies:
'@typescript-eslint/types': 8.0.0-alpha.39
'@typescript-eslint/visitor-keys': 8.0.0-alpha.39
debug: 4.3.5
globby: 11.1.0
is-glob: 4.0.3
minimatch: 9.0.4
semver: 7.6.2
ts-api-utils: 1.3.0(typescript@5.5.3)
optionalDependencies:
typescript: 5.5.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/typescript-estree@8.0.0-alpha.40(typescript@5.5.3)':
dependencies:
'@typescript-eslint/types': 8.0.0-alpha.40
'@typescript-eslint/visitor-keys': 8.0.0-alpha.40
'@typescript-eslint/types': 8.0.0-alpha.41
'@typescript-eslint/visitor-keys': 8.0.0-alpha.41
debug: 4.3.5
globby: 11.1.0
is-glob: 4.0.3
@ -3664,23 +3630,23 @@ snapshots:
- supports-color
- typescript
'@typescript-eslint/utils@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)':
'@typescript-eslint/utils@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)':
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))
'@typescript-eslint/scope-manager': 7.15.0
'@typescript-eslint/types': 7.15.0
'@typescript-eslint/typescript-estree': 7.15.0(typescript@5.5.3)
'@typescript-eslint/scope-manager': 7.16.0
'@typescript-eslint/types': 7.16.0
'@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.3)
eslint: 8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)
transitivePeerDependencies:
- supports-color
- typescript
'@typescript-eslint/utils@8.0.0-alpha.39(eslint@9.6.0)(typescript@5.5.3)':
'@typescript-eslint/utils@8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3)':
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@9.6.0)
'@typescript-eslint/scope-manager': 8.0.0-alpha.39
'@typescript-eslint/types': 8.0.0-alpha.39
'@typescript-eslint/typescript-estree': 8.0.0-alpha.39(typescript@5.5.3)
'@typescript-eslint/scope-manager': 8.0.0-alpha.41
'@typescript-eslint/types': 8.0.0-alpha.41
'@typescript-eslint/typescript-estree': 8.0.0-alpha.41(typescript@5.5.3)
eslint: 9.6.0
transitivePeerDependencies:
- supports-color
@ -3691,19 +3657,14 @@ snapshots:
'@typescript-eslint/types': 7.14.1
eslint-visitor-keys: 3.4.3
'@typescript-eslint/visitor-keys@7.15.0':
'@typescript-eslint/visitor-keys@7.16.0':
dependencies:
'@typescript-eslint/types': 7.15.0
'@typescript-eslint/types': 7.16.0
eslint-visitor-keys: 3.4.3
'@typescript-eslint/visitor-keys@8.0.0-alpha.39':
'@typescript-eslint/visitor-keys@8.0.0-alpha.41':
dependencies:
'@typescript-eslint/types': 8.0.0-alpha.39
eslint-visitor-keys: 3.4.3
'@typescript-eslint/visitor-keys@8.0.0-alpha.40':
dependencies:
'@typescript-eslint/types': 8.0.0-alpha.40
'@typescript-eslint/types': 8.0.0-alpha.41
eslint-visitor-keys: 3.4.3
'@ungap/structured-clone@1.2.0': {}
@ -4312,9 +4273,9 @@ snapshots:
optionalDependencies:
source-map: 0.6.1
eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))):
eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))):
dependencies:
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))
eslint-import-resolver-node@0.3.9:
dependencies:
@ -4324,11 +4285,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.8.1(@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)):
eslint-module-utils@2.8.1(@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
'@typescript-eslint/parser': 7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
eslint: 8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)
eslint-import-resolver-node: 0.3.9
transitivePeerDependencies:
@ -4361,7 +4322,7 @@ snapshots:
- supports-color
- typescript
eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)):
eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)):
dependencies:
array-includes: 3.1.8
array.prototype.findlastindex: 1.2.5
@ -4371,7 +4332,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))
hasown: 2.0.2
is-core-module: 2.14.0
is-glob: 4.0.3
@ -4382,7 +4343,7 @@ snapshots:
semver: 6.3.1
tsconfig-paths: 3.15.0
optionalDependencies:
'@typescript-eslint/parser': 7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
'@typescript-eslint/parser': 7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
@ -4429,19 +4390,19 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-plugin-unused-imports@3.2.0(@typescript-eslint/eslint-plugin@7.15.0(@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)):
eslint-plugin-unused-imports@3.2.0(@typescript-eslint/eslint-plugin@7.16.0(@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)):
dependencies:
eslint: 8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi)
eslint-rule-composer: 0.3.0
optionalDependencies:
'@typescript-eslint/eslint-plugin': 7.15.0(@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
'@typescript-eslint/eslint-plugin': 7.16.0(@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
eslint-plugin-unused-imports@4.0.0(@typescript-eslint/eslint-plugin@7.15.0(@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@9.6.0):
eslint-plugin-unused-imports@4.0.0(@typescript-eslint/eslint-plugin@7.16.0(@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@9.6.0):
dependencies:
eslint: 9.6.0
eslint-rule-composer: 0.3.0
optionalDependencies:
'@typescript-eslint/eslint-plugin': 7.15.0(@typescript-eslint/parser@7.15.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
'@typescript-eslint/eslint-plugin': 7.16.0(@typescript-eslint/parser@7.16.0(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3))(eslint@8.57.0(patch_hash=wy5a2dwvtxac2ygzwebqqjurgi))(typescript@5.5.3)
eslint-rule-composer@0.3.0: {}
@ -5988,11 +5949,11 @@ snapshots:
is-typed-array: 1.1.13
possible-typed-array-names: 1.0.0
typescript-eslint@8.0.0-alpha.39(eslint@9.6.0)(typescript@5.5.3):
typescript-eslint@8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.0.0-alpha.39(@typescript-eslint/parser@8.0.0-alpha.39(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0)(typescript@5.5.3)
'@typescript-eslint/parser': 8.0.0-alpha.39(eslint@9.6.0)(typescript@5.5.3)
'@typescript-eslint/utils': 8.0.0-alpha.39(eslint@9.6.0)(typescript@5.5.3)
'@typescript-eslint/eslint-plugin': 8.0.0-alpha.41(@typescript-eslint/parser@8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0)(typescript@5.5.3)
'@typescript-eslint/parser': 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3)
'@typescript-eslint/utils': 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3)
optionalDependencies:
typescript: 5.5.3
transitivePeerDependencies:

View file

@ -79,7 +79,7 @@ const IGNORED_DISCORD_ERRORS: (RegExp | string)[] = [
function toCodeBlock(s: string, indentation = 0, isDiscord = false) {
s = s.replace(/```/g, "`\u200B`\u200B`");
const indentationStr = Array(!isDiscord ? indentation : 0).fill(" ").join("");
const indentationStr = " ".repeat(!isDiscord ? indentation : 0);
return `\`\`\`\n${s.split("\n").map(s => indentationStr + s).join("\n")}\n${indentationStr}\`\`\``;
}