Skip to content

Commit

Permalink
Add require function to implementation stores
Browse files Browse the repository at this point in the history
  • Loading branch information
Davilarek committed Feb 22, 2024
1 parent a4e0f5c commit 159d03c
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 7 deletions.
39 changes: 37 additions & 2 deletions src/api/RuntimeGenerators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function createFunctionFromObjectProperty(objectName: string, property: s
return generatedFunction;
}

import { FunctionImplementation, doesImplement, implementationStores, initStores } from "../common/index.js";
import { FunctionImplementation, __requireInternal, doesImplement, implementationStores, initStores } from "../common/index.js";
import { createJavaScriptFromObject } from "../utils.js";
import { parse } from "@babel/parser";
import { IModImplementation } from "./ModImplementation.js";
Expand Down Expand Up @@ -65,13 +65,48 @@ export async function addCode(mod: IModImplementation) {
if (Object.prototype.hasOwnProperty.call(implementationStores[key].implementationStore, key2)) {
const element = implementationStores[key].implementationStore[key2];
if (doesImplement(mod, key, key2)) continue;
if (element.func.toString().includes(__requireInternal.name)) {
// const regex = new RegExp(__requireInternal.name + "\\(([^)]+)\\)", 'g');
// const match = element.func.toString().match(regex);
// if (!match)
// continue;
// const args = match[1].split(',').map(value => value.trim());
// args.shift();
// console.log(args);
// // const constructed2 = element.func.toString().replace(new RegExp(__requireInternal.name + "\\([^,]+,\\s*", 'g'), "globalThis.implementationStores_require(") + "}.func";
// // element.func = new Function("return {" + constructed2)();
// // element.func = (mod as { [key: string]: any })[args[0]][args[1]];
const regexPattern = new RegExp(`${__requireInternal.name}\\(([^)]+)\\)`, "g");
let match;
while ((match = regexPattern.exec(element.func.toString())) !== null) {
const argsStr = match[1];
const args = argsStr.split(',').map(x => x.trim()).map(x => x.startsWith("\"") && x.endsWith("\"") ? x.slice(1, -1) : x);
args.shift();

// const replacement = "globalThis.implementationStores_require(" + someValues.join(",") + ")";
// const result = element.func.toString().replace(match[0], replacement);
try {
const findResult = (mod as { [key: string]: any })[args[0]][args[1]];
// element.func = findResult;
element.func = new Function("return {" + element.func.toString().replace(match[0], `${findResult.object}.${findResult.property}`) + "}.func")();
}
catch (error) {
console.error(error);
const replacement = `globalThis.implementationStores_require(globalThis.implementationStores["${args[0]}"]["${args[1]}"])`;
element.func = new Function("return {" + element.func.toString().replace(match[0], replacement) + "}.func")();
}
}
}
constructed[key][key2] = element;
}
}
}
}
// const rawCode = "globalThis.implementationStores = {\n" + getMain(serializer).serialize(constructed) + "\n}";
const rawCode = "globalThis.implementationStores = (" + createJavaScriptFromObject(constructed, true) + ")";
const req = (target: any) => new Function("target", "return {" + target.func + "}.func;")(target);
const rawCode =
`globalThis.implementationStores = (${createJavaScriptFromObject(constructed, true)});
globalThis.implementationStores_require = ${req.toString()};`; // TODO: Remove hardcoded paths
// console.log(rawCode);
const rawCodeAst = parse(rawCode);
return rawCodeAst.program.body;
Expand Down
15 changes: 13 additions & 2 deletions src/common/WebpackApi.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FunctionImplementation, require } from "./index.js";
import { FunctionImplementation, __requireInternal } from "./index.js";
import { IModImplementation } from "../api/ModImplementation.js";

// const reservedData = {} as { [key: string]: any };
Expand Down Expand Up @@ -39,7 +39,8 @@ const implementationStore = {
supplies: "getByStrings",
data: null,
func(...strings) {
const getModule = require(targetMod, "Webpack", "getModule");
__requireInternal(targetMod, "WebpackApi", "test")!();
const getModule = __requireInternal(targetMod, "WebpackApi", "getModule");
if (!getModule)
throw new Error("Unimplemented");
return getModule((module: any) => {
Expand All @@ -55,6 +56,16 @@ const implementationStore = {
});
},
}),
test: new FunctionImplementation({
data: null,
depends: ["getByStrings"],
supplies: "test",
// eslint-disable-next-line @typescript-eslint/no-unused-vars
func(...args: any[]) {
debugger;
return "among us";
},
}),
} as { [key: string]: FunctionImplementation };
export {
implementationStore,
Expand Down
4 changes: 2 additions & 2 deletions src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function doesImplement(mod: IModImplementation, category: string, method:
return getKeyValue(categoryObj, method as never) != undefined;
}

export function require(mod: IModImplementation, category: string, method: string) {
export function __requireInternal(mod: IModImplementation, category: string, method: string) {
if (doesImplement(mod, category, method)) {
const categoryObj = getKeyValue(mod, category as keyof IModImplementation);
return getKeyValue(categoryObj, method as never);
Expand All @@ -63,5 +63,5 @@ export function require(mod: IModImplementation, category: string, method: strin
const foundImplementation = implementationStores[category].implementationStore[method];
if (foundImplementation == undefined)
return null; // depends failed
return createFunctionFromObjectProperty(`globalThis.implementationStores.${category}`, method); // this hurts me
return createFunctionFromObjectProperty(`globalThis.implementationStores.${category}`, method); // TODO: Remove hardcoded paths
}
20 changes: 19 additions & 1 deletion src/converter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { ParseResult } from "@babel/parser";
import { File, Identifier, ImportDeclaration, ImportSpecifier, MemberExpression, Statement } from "@babel/types";
import { File, Identifier, ImportDeclaration, ImportSpecifier, MemberExpression, Statement, callExpression, identifier, memberExpression, stringLiteral } from "@babel/types";
import { NonFunctionType, getKeyValue, myPackageName } from "./utils.js";
import { IModImplementation } from "./api/ModImplementation";
import { addCode } from "./api/RuntimeGenerators.js";
Expand Down Expand Up @@ -117,6 +117,7 @@ export default async function (ast: ParseResult<File>, targetedDiscordModApiLibr
const trueImportsToRemove =
importStatements.filter((_, index) => importsToRemove.includes(index));
const parsedBodyWithoutOurImports = parsedBody.filter((item, index) => !trueImportsToRemove.includes(parsedBody[index]));
parsedBodyWithoutOurImports.unshift(...await addCode(targetedDiscordModApiLibrary.default));
for (let index = 0; index < parsedBodyWithoutOurImports.length; index++) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const element = parsedBodyWithoutOurImports[index];
Expand All @@ -140,6 +141,23 @@ export default async function (ast: ParseResult<File>, targetedDiscordModApiLibr
const targetClass: IModImplementation[keyof IModImplementation] = propDesc.value ?? propDesc.get!(); // TODO: don't make value `any`
if (targetClass == undefined)
continue;
if (typeof targetClass === "object" && !((trueObj.property as Identifier).name as keyof typeof targetClass in targetClass)) {
const originalObj = (trueObj.object as Identifier).name;
const originalProp = (trueObj.property as Identifier).name;
// (trueObj.object as Identifier).name = "globalThis.implementationStores_require"; // TODO: Remove hardcoded paths
// (trueObj.property as Identifier).name = (trueObj.property as Identifier).name + ".func";
for (const prop of Object.getOwnPropertyNames(trueObj)) {
// @ts-expect-error well
delete trueObj[prop];
}
// const newCallExpr = callExpression(memberExpression(identifier("globalThis"), identifier("implementationStores_require")), [stringLiteral(`globalThis.implementationStores["${originalObj}"]["${originalProp}"]`)]);
const newCallExpr = callExpression(memberExpression(identifier("globalThis"), identifier("implementationStores_require")), [
// stringLiteral(`globalThis.implementationStores["${originalObj}"]["${originalProp}"]`),
memberExpression(memberExpression(memberExpression(identifier("globalThis"), identifier("implementationStores")), identifier(originalObj)), identifier(originalProp)),
]);
Object.assign(trueObj, newCallExpr);
continue;
}
const replacementObject = getKeyValue(targetClass, (trueObj.property as Identifier).name as keyof typeof targetClass) as { object: string, property: string };
(trueObj.object as Identifier).name = replacementObject.object;
(trueObj.property as Identifier).name = replacementObject.property;
Expand Down

0 comments on commit 159d03c

Please sign in to comment.