Skip to content
This repository was archived by the owner on Feb 20, 2025. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ dist
src/converter copy.ts
test/sample/betterdiscord/index.js
test/sample/replugged/index.js
test/sample/vencord/index.js
3 changes: 3 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export const IMPLEMENTATION_STORES_PATH_SOURCE = "globalThis";
export const IMPLEMENTATION_STORES_PATH_VAR_NAME = "implementationStores";
export const IMPLEMENTATION_STORES_PATH_REQ = IMPLEMENTATION_STORES_PATH_VAR_NAME + "_require";
export const BV_PATCHER_COMMIT_HASH = "4f566d27074995882422ce3874236a514890263a";
export const BV_PATCHER_SOURCE_URL = (commitHash: string) => `https://github.com/Davilarek/Vencord/raw/${commitHash}/src/plugins/bdCompatLayer/stuffFromBD.js`;
export const VENCORD_PATCHER_GLOBAL_NAME = "VencordSharedPatcher";
2 changes: 1 addition & 1 deletion src/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,5 +225,5 @@ export default async function (ast: ParseResult<File>, targetedDiscordModApiLibr
parsedBodyWithoutOurImports.unshift(...await addCode(targetedDiscordModApiLibrary.default));
if ((targetedDiscordModApiLibrary as { default: IModImplementation } & { convertFormat: (ast_: Statement[]) => Statement[] }).convertFormat == undefined)
return parsedBodyWithoutOurImports;
return (targetedDiscordModApiLibrary as { default: IModImplementation } & { convertFormat: (ast_: Statement[]) => Statement[] }).convertFormat(parsedBodyWithoutOurImports);
return await (targetedDiscordModApiLibrary as { default: IModImplementation } & { convertFormat: (ast_: Statement[]) => Statement[] }).convertFormat(parsedBodyWithoutOurImports);
}
119 changes: 119 additions & 0 deletions src/converters/vencord.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { IBaseWebpackApi } from "../api/Webpack.js";
import { parse } from "@babel/parser";
import { IBasePatcherApi } from "../api/Patcher.js";
import { IModImplementation } from "../api/ModImplementation.js";
import { createFunctionFromObjectProperty, createFunctionWithWrapperNeeded } from "../api/RuntimeGenerators.js";
import { addComment, assignmentExpression, ClassDeclaration, classExpression, emptyStatement, ExportDefaultDeclaration, identifier, isExportDefaultDeclaration, logicalExpression, memberExpression, removeComments, Statement, toExpression, toStatement, traverse, variableDeclaration, variableDeclarator } from "@babel/types";
import { BV_PATCHER_COMMIT_HASH, BV_PATCHER_SOURCE_URL, VENCORD_PATCHER_GLOBAL_NAME } from "../constants.js";

class VCWebpackApi implements IBaseWebpackApi {
get getModule() {
return createFunctionFromObjectProperty("Vencord.Webpack", "find");
// return undefined as unknown as any;
// return createFunctionThatIsMissing();
// return { wrapperName: "getModule" } as any;
}
}

class VCPatcherApi implements IBasePatcherApi {
get constructor_() {
return createFunctionWithWrapperNeeded(VENCORD_PATCHER_GLOBAL_NAME, "undefined", "Patcher_constructor") as any;
}
// constructor() {
// return this.constructor_;
// }
internalId: undefined;
get unpatchAll() {
return createFunctionWithWrapperNeeded(VENCORD_PATCHER_GLOBAL_NAME, "unpatchAll", "unpatchAllWrapper");
}
get after() {
return createFunctionWithWrapperNeeded(VENCORD_PATCHER_GLOBAL_NAME, "after", "afterWrapper");
}
get before() {
return createFunctionWithWrapperNeeded(VENCORD_PATCHER_GLOBAL_NAME, "before", "beforeWrapper");
}
get instead() {
return createFunctionWithWrapperNeeded(VENCORD_PATCHER_GLOBAL_NAME, "instead", "insteadWrapper");
}
}

export async function convertFormat(ast: Statement[]) {
const response = await fetch(BV_PATCHER_SOURCE_URL(BV_PATCHER_COMMIT_HASH));
const parsed = parse((await response.text()).replace("BdApi.Webpack.findByUniqueProperties", "Vencord.Webpack.findByProps"), { sourceType: "module" }).program.body;
const patcherClass = parsed.find(x => x.type == "ClassDeclaration" && x.id?.name == "Patcher") as ClassDeclaration;
if (!patcherClass)
return ast;
const originalComment = patcherClass.leadingComments;
traverse(patcherClass, {
enter(node) {
removeComments(node);
},
});
// patcherClass.leadingComments = originalComment;
const memberExpr = memberExpression(identifier("window"), identifier(VENCORD_PATCHER_GLOBAL_NAME));
const assigExpr = assignmentExpression("=", memberExpr, logicalExpression("??", memberExpr, classExpression(null, null, patcherClass.body)));
assigExpr.leadingComments = originalComment;
ast.unshift(toStatement(assigExpr));
ast.unshift(addComment(emptyStatement(), "leading", " eslint-disable simple-header/header "));

for (let i = 0; i < ast.length; i++) {
if (isExportDefaultDeclaration(ast[i])) {
const exportDefault = ast[i] as ExportDefaultDeclaration;
const declaration = exportDefault.declaration as ClassDeclaration;
const variableName = 'defaultExport';
const varDeclarator = variableDeclarator(identifier(variableName), toExpression(declaration));
const varDeclaration = variableDeclaration('const', [varDeclarator]);
ast[i] = varDeclaration;
const pluginTemplateCode = `
import definePlugin from "@utils/types";
import { wreq, beforeInitListeners } from "@webpack";
if (Array.prototype.find.call([...beforeInitListeners], x => x && x.toString().includes("writeable")) === undefined) {
beforeInitListeners.add(() => {
console.log("Making exports writeable...");
if (wreq.d.toString().includes("set:"))
{
console.log("Already writeable");
return;
}
wreq.d = (target, exports) => {
for (const key in exports) {
if (!Reflect.has(exports, key)) continue;
Object.defineProperty(target, key, {
get: () => exports[key](),
set: v => { exports[key] = () => v; },
enumerable: true,
configurable: false
});
}
};
});
}
const thePlugin = {
name: "${declaration.id?.name}",
description: "${declaration.id?.name} plugin",
authors: [
{
id: 0n,
name: "Anonymous"
}
],
instance: (() => new ${variableName}())(),
start() {
this.instance.start();
},
stop() {
this.instance.stop();
},
};
export default definePlugin(thePlugin);`;
ast.push(...parse(pluginTemplateCode, { sourceType: "module" }).program.body);
break;
}
}
return ast;
}

export default {
WebpackApi: new VCWebpackApi(),
PatcherApi: VCPatcherApi.prototype,
} as IModImplementation;
Empty file added test/sample/vencord/.gitkeep
Empty file.