diff --git a/.github/workflows/automated-test.yml b/.github/workflows/automated-test.yml
new file mode 100644
index 0000000..cb89963
--- /dev/null
+++ b/.github/workflows/automated-test.yml
@@ -0,0 +1,19 @@
+name: Node.js CI
+
+on: [push, pull_request]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Use Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: '20.x'
+ - uses: pnpm/action-setup@v3
+ with:
+ version: 8
+ - run: pnpm i
+ - run: pnpm run build
+ - run: pnpm test
diff --git a/package.json b/package.json
index 6a6eb49..bb72c78 100644
--- a/package.json
+++ b/package.json
@@ -7,9 +7,10 @@
"discord-mod-compiler": "dist/cli.js"
},
"scripts": {
- "test": "npm run cli ./test/sample/index.js RePlugged",
+ "test": "tsc && node ./test/check-converters.js",
"cli": "tsc && node dist/cli.js",
"cli-debug": "tsc && node --inspect dist/cli.js",
+ "cli-nobuild": "node dist/cli.js",
"build": "tsc"
},
"keywords": [],
diff --git a/src/api/ModImplementation.ts b/src/api/ModImplementation.ts
new file mode 100644
index 0000000..5ffae34
--- /dev/null
+++ b/src/api/ModImplementation.ts
@@ -0,0 +1,9 @@
+import { WebpackApi } from "./Webpack.js";
+
+export interface IModImplementation {
+ WebpackApi: typeof WebpackApi,
+ /**
+ * shall be true when a mod requires the Dev to bundle their code into single file
+ */
+ importsForbidden?: boolean,
+}
diff --git a/src/api/index.ts b/src/api/RuntimeGenerators.ts
similarity index 77%
rename from src/api/index.ts
rename to src/api/RuntimeGenerators.ts
index 18cd219..f7ecb4d 100644
--- a/src/api/index.ts
+++ b/src/api/RuntimeGenerators.ts
@@ -1,14 +1,3 @@
-import IBaseWebpackApi, { WebpackApi } from "./Webpack/index.js";
-
-interface ModImplementation {
- WebpackApi: typeof WebpackApi,
- /**
- * shall be true when a mod requires the Dev to bundle their code into single file
- */
- importsForbidden?: boolean,
-}
-export { IBaseWebpackApi, WebpackApi, ModImplementation };
-
/**
* Creates a function from a given path that gets resolved at runtime.
* @param path - The path to create the function from.
diff --git a/src/api/Webpack/index.ts b/src/api/Webpack.ts
similarity index 85%
rename from src/api/Webpack/index.ts
rename to src/api/Webpack.ts
index 15afbb3..7909bbc 100644
--- a/src/api/Webpack/index.ts
+++ b/src/api/Webpack.ts
@@ -1,7 +1,6 @@
-interface IBaseWebpackApi {
+export interface IBaseWebpackApi {
getModule(filter: (match: any) => boolean): any;
}
-export default IBaseWebpackApi;
class DummyWebpackApi implements IBaseWebpackApi {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
diff --git a/src/cli.ts b/src/cli.ts
index e841548..a56a074 100644
--- a/src/cli.ts
+++ b/src/cli.ts
@@ -6,10 +6,10 @@ import converter from "./converter.js";
import { File } from "@babel/types";
import { myPackageName } from "./utils.js";
import { transformSync } from "@babel/core";
-import { ModImplementation } from "./api/index.js";
+import { IModImplementation } from "./api/ModImplementation.js";
if (process.argv.length != 4) {
- console.log("Usage:\n\t" + myPackageName + " \nExample:\n\t" + myPackageName + " ./index.js BetterDiscord");
+ console.error(`Usage:\n\t${myPackageName} \nExample:\n\t${myPackageName} ./index.js BetterDiscord`);
process.exit(1);
}
@@ -42,7 +42,7 @@ if (!isClientModSupported) {
const filler = import(url.pathToFileURL(`${__dirname}/converters/${targetDiscordMod}.js`).href);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
-filler.then((x: { default: ModImplementation }) => {
+filler.then((x: { default: IModImplementation }) => {
if (x.default.importsForbidden)
console.warn('\x1b[33m%s\x1b[0m', `Warning: Target mod ${targetDiscordMod} requires your code to be bundled into single file`);
const out = converter(ast as File & { errors: [] }, x);
diff --git a/src/converter.ts b/src/converter.ts
index eced9f6..059f3a8 100644
--- a/src/converter.ts
+++ b/src/converter.ts
@@ -2,7 +2,7 @@
import { ParseResult } from "@babel/parser";
import { File, Identifier, ImportDeclaration, ImportSpecifier, MemberExpression, Statement } from "@babel/types";
import { NonFunctionType, myPackageName } from "./utils.js";
-import { ModImplementation } from "./api/index.js";
+import { IModImplementation } from "./api/ModImplementation";
function removeASTLocation(ast: Statement[] | Statement) {
if (Array.isArray(ast)) {
@@ -95,7 +95,7 @@ function deepFind(obj: any, path: string): K | undefined {
const getKeyValue = (obj: T, key: K): T[K] => obj[key];
-export default function (ast: ParseResult, targetedDiscordModApiLibrary: { default: ModImplementation }): Statement[] {
+export default function (ast: ParseResult, targetedDiscordModApiLibrary: { default: IModImplementation }): Statement[] {
const parsedBody = ast.program.body;
const importStatements = parsedBody.filter(x => x.type == "ImportDeclaration");
const importsToBake = [];
@@ -134,11 +134,11 @@ export default function (ast: ParseResult, targetedDiscordModApiLibrary: {
console.log(trueObj);
if (trueObj != undefined && importsToBake.includes((trueObj.object as Identifier).name)) {
removeASTLocation(trueObj as unknown as Statement);
- const propDesc = Object.getOwnPropertyDescriptor(targetedDiscordModApiLibrary.default, (trueObj.object as Identifier).name as keyof ModImplementation);
+ const propDesc = Object.getOwnPropertyDescriptor(targetedDiscordModApiLibrary.default, (trueObj.object as Identifier).name as keyof IModImplementation);
if (!propDesc)
continue;
// const targetClass = targetedDiscordModApiLibrary.default[(trueObj.object as Identifier).name];
- const targetClass: ModImplementation[keyof ModImplementation] = propDesc.value ?? propDesc.get!(); // TODO: don't make value `any`
+ const targetClass: IModImplementation[keyof IModImplementation] = propDesc.value ?? propDesc.get!(); // TODO: don't make value `any`
if (targetClass == undefined)
continue;
const replacementObject = getKeyValue(targetClass, (trueObj.property as Identifier).name as keyof typeof targetClass) as { object: string, property: string };
diff --git a/src/converters/betterdiscord.ts b/src/converters/betterdiscord.ts
index f8f2500..783d0ac 100644
--- a/src/converters/betterdiscord.ts
+++ b/src/converters/betterdiscord.ts
@@ -1,4 +1,6 @@
-import { IBaseWebpackApi, ModImplementation, createFunctionFromObjectProperty } from "../api/index.js";
+import { IModImplementation } from "../api/ModImplementation.js";
+import { createFunctionFromObjectProperty } from "../api/RuntimeGenerators.js";
+import { IBaseWebpackApi } from "../api/Webpack.js";
class BDWebpackApi implements IBaseWebpackApi {
get getModule() {
@@ -9,4 +11,4 @@ class BDWebpackApi implements IBaseWebpackApi {
export default {
WebpackApi: new BDWebpackApi(),
importsForbidden: true,
-} as ModImplementation;
+} as IModImplementation;
diff --git a/src/converters/replugged.ts b/src/converters/replugged.ts
index 6559957..702d4b5 100644
--- a/src/converters/replugged.ts
+++ b/src/converters/replugged.ts
@@ -1,4 +1,6 @@
-import { IBaseWebpackApi, ModImplementation, createFunctionFromObjectProperty } from "../api/index.js";
+import { IModImplementation } from "../api/ModImplementation.js";
+import { createFunctionFromObjectProperty } from "../api/RuntimeGenerators.js";
+import { IBaseWebpackApi } from "../api/Webpack.js";
class RPWebpackApi implements IBaseWebpackApi {
get getModule() {
@@ -8,4 +10,4 @@ class RPWebpackApi implements IBaseWebpackApi {
export default {
WebpackApi: new RPWebpackApi(),
-} as ModImplementation;
+} as IModImplementation;
diff --git a/src/index.ts b/src/index.ts
index d9e95da..3c7b07e 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1 +1 @@
-export * from "./api/index.js";
+export * from './api/Webpack.js';
\ No newline at end of file
diff --git a/test/check-converters.js b/test/check-converters.js
new file mode 100644
index 0000000..1275392
--- /dev/null
+++ b/test/check-converters.js
@@ -0,0 +1,20 @@
+import fs from 'fs';
+import path from 'path';
+import { execSync } from 'child_process';
+
+// Read the files in ./src/converters
+const files = fs.readdirSync('./src/converters');
+
+// Filter .ts files and remove extension
+const tsFiles = files.filter(file => path.extname(file) === '.ts').map(file => path.basename(file, '.ts'));
+
+for (const file of tsFiles) {
+ console.log(`Testing ${file}`);
+
+ try {
+ execSync(`npm run cli-nobuild ./test/sample/index.js ${file}`, { stdio: 'inherit' });
+ } catch (error) {
+ console.error(`Error in ${file}`);
+ process.exit(1);
+ }
+}
\ No newline at end of file