Dynamic access to Operators in both front and backend

This commit is contained in:
Felix Kaspar
2024-02-23 23:48:03 +01:00
parent 244fb36195
commit 644e0ceae9
18 changed files with 593 additions and 74 deletions

View File

@@ -0,0 +1,3 @@
declare interface ImportMeta {
compileTime: <T>(file: string) => T
}

View File

@@ -1,8 +1,7 @@
import { PdfFile } from "../wrappers/PdfFile.js";
import { Sorts } from "./common/pageIndexesSorting.js";
import { getPages } from "./common/getPagesByIndex.js";
import { parsePageIndexSpecification } from "./common/pageIndexesUtils.js";
import { PdfFile } from "../wrappers/PdfFile";
import { Sorts } from "./common/pageIndexesSorting";
import { getPages } from "./common/getPagesByIndex";
import { parsePageIndexSpecification } from "./common/pageIndexesUtils";
export interface ArrangePagesParamsType {
file: PdfFile;

View File

@@ -1,34 +0,0 @@
import { Operator } from "../functions";
import i18next from "i18next";
// TODO: Import other Operators (should make this dynamic imports)
i18next.loadNamespaces("impose", (err, t) => { if (err) throw err; });
import { Impose } from "../functions/impose";
export const Operators = {
Impose: Impose
};
// TODO: Convert this to a map or similar
export function getOperatorByName(name: string): typeof Operator | undefined {
let foundClass: typeof Operator | undefined = undefined;
// Loop over each default export
Object.entries(Operators).some(([className, exportedClass]) => {
// Check if the exported item is a class
if (typeof exportedClass === "function" && exportedClass.prototype) {
if (exportedClass.type === name) {
foundClass = exportedClass;
return true; // Stop the iteration
}
}
return false;
});
return foundClass;
}
export function listOperatorNames(): string[] {
// TODO: Implement this
return ["impose"];
}

View File

@@ -0,0 +1,38 @@
import fs from "fs";
import path from "path";
import {
CompileTimeFunctionArgs,
CompileTimeFunctionResult,
} from "vite-plugin-compile-time"
function getAllJsFiles(directory) {
const jsFiles = [];
// Synchronously read the contents of the directory
const files = fs.readdirSync(directory);
// Iterate through the files and filter out the JavaScript files
files.forEach((file) => {
const filePath = path.join(directory, file)
const isJsFile = fs.statSync(filePath).isFile() && path.extname(filePath) === '.ts';
if (isJsFile) {
const baseName = path.basename(filePath, '.ts');
if(baseName != "index") {
jsFiles.push(baseName);
}
}
});
return jsFiles;
}
export default async (
args: CompileTimeFunctionArgs,
): Promise<CompileTimeFunctionResult> => {
const jsFiles = getAllJsFiles(__dirname + "/../functions/");
return {
data: jsFiles,
// Trigger rebuild when watched files change
watchFiles: [__filename],
}
}

View File

@@ -0,0 +1,24 @@
import { Operator } from "../functions";
import i18next from "i18next";
function getCompileTimeOperatorList(): string[] {
return import.meta.compileTime("./listOperatorsInDir.ts");
}
export async function getOperatorByName(name: string): Promise<typeof Operator | undefined> {
// Check if exists
if(!getCompileTimeOperatorList().includes(name)) return;
i18next.loadNamespaces(name, (err, t) => { if (err) throw err; });
return (await import("../functions/" + name + ".ts"))[capitalizeFirstLetter(name)];
}
export function listOperatorNames(): string[] {
const availableOperators = getCompileTimeOperatorList();
// TODO: Implement this
return availableOperators;
}
function capitalizeFirstLetter(string: String) {
return string.charAt(0).toUpperCase() + string.slice(1);
}

View File

@@ -3,10 +3,10 @@ import { Action, WaitAction } from "../../declarations/Action";
import { PdfFile } from "../wrappers/PdfFile";
import { Progress } from "../functions";
import { validateOperations } from "./validateOperations";
import { getOperatorByName } from "./getOperatorByName";
import { getOperatorByName } from "./operatorAccessor";
export async function traverseOperations(operations: Action[], input: PdfFile[], progressCallback: (state: Progress) => void): Promise<PdfFile[]> {
const validationResult = validateOperations(operations);
const validationResult = await validateOperations(operations);
if(!validationResult.valid) {
return Promise.reject({validationError: validationResult.reason});
}
@@ -47,7 +47,7 @@ export async function traverseOperations(operations: Action[], input: PdfFile[],
}
break;
default:
const operator = getOperatorByName(action.type);
const operator = await getOperatorByName(action.type);
if(operator) {
const operation = new operator(action);
input = await operation.run(input, progressCallback);

View File

@@ -1,9 +1,9 @@
import { Operator } from "../functions";
import { Action } from "../../declarations/Action";
import { getOperatorByName } from "./getOperatorByName";
import { getOperatorByName } from "./operatorAccessor";
/** This function validates the "workflow-json" from the API */
export function validateOperations(actions: Action[]): { valid: boolean, reason?: string} {
export async function validateOperations(actions: Action[]): Promise<{ valid: boolean, reason?: string}> {
const done: Action[] = [];
for (const action of actions) {
@@ -15,7 +15,7 @@ export function validateOperations(actions: Action[]): { valid: boolean, reason?
continue;
}
const operator = getOperatorByName(action.type);
const operator = await getOperatorByName(action.type);
if(!operator) {
return { valid: false, reason: `action.type ${action.type} does not exist` };
}
@@ -35,7 +35,7 @@ export function validateOperations(actions: Action[]): { valid: boolean, reason?
}
for (const afterDoneChild of done[childAction.values.id]?.actions || []) {
const receivingOperator = getOperatorByName(afterDoneChild.type);
const receivingOperator = await getOperatorByName(afterDoneChild.type);
if (receivingOperator === undefined) {
return { valid: false, reason: `action.type ${afterDoneChild.type} does not exist.` };
} else if (!ioCompatible(operator, receivingOperator)) {
@@ -47,7 +47,7 @@ export function validateOperations(actions: Action[]): { valid: boolean, reason?
return { valid: false, reason: "There shouldn't be a done action here." };
}
else {
const receivingOperator = getOperatorByName(childAction.type);
const receivingOperator = await getOperatorByName(childAction.type);
if (receivingOperator === undefined) {
return { valid: false, reason: `action.type ${childAction.type} does not exist.` };
} else if (!ioCompatible(operator, receivingOperator)) {
@@ -56,7 +56,7 @@ export function validateOperations(actions: Action[]): { valid: boolean, reason?
}
}
const validationResult = validateOperations(action.actions);
const validationResult = await validateOperations(action.actions);
if(!validationResult.valid) {
return validationResult;