Updated Contribute & a little bit of cleanup

This commit is contained in:
Felix Kaspar 2023-12-27 23:55:11 +01:00
parent 45d5f2c533
commit 762fa850f1
6 changed files with 30 additions and 107 deletions

View File

@ -8,19 +8,29 @@ This file should introduce you with the concepts and tools used in this project.
- [opencv-wasm](https://www.npmjs.com/package/opencv-wasm) - ?-wasm
- [pdfjs](https://www.npmjs.com/package/pdfjs-dist) - js
## Nomenclature
- API - Probably refers to the “normal“ API of spdf v2 without workflows unless otherwise noted.
- Workflow - Either the express-endpoint for running workflows or the user defined workflow-json
- Action - A sub-element of a workflow describing what operation should run on the inputted file / output of the last action.
- Operation - The actual function that will run on the pdf, including parameters.
- Operator - The actual code/implementation of the Operation (e.g. impose.ts) OR The parent class of every Operator.
- Validator - A function that makes sure things are as they should be. Every Operator must have one.
- Decorator - Explanations and Human Readable names of fields, these will be displayed in the frontend and used to provide better errors for the (workflow-)API
## Folder structure
- (abandoned) client-ionic- An old test of
- client-tauri - The frontend
- (abandoned) client-vanilla - The initial test to see if it is possible to run Operators in the browser environment of the user in addition to having a backend. Will be removed once development on the fronend/client-tauri has started.
- server-node - Functions and Classes that are shared between frontend and backend e.g. Operators
## Basic Setup
- Install/Update Node (>v20.9.0) & NPM(>10.2.1)
- To install all dependecies `npm run update-all-dependencies` (in [root](/))
- To test your current setup and boot a complete install of spdf v2 run `npm run dev-all` (in [root](/))
## Adding a PDF Operation
StirlingPDF aims to support as many types of operations as possible, including some that cannot be executed in the client. Because of this, we have decided to move some of the shared functionality into it's own node module so that it can be shared by both client and server.
### Adding a shared (server + client) operation
1. Add the code for the operation to a new file in the [functions folder](/shared-operations/functions/).
> **NOTE:** many of the functions in these files use **dependency injection** (see impose for an example).
>
> **Explanation:** Because some libraries need to be imported in different ways. We import the library as needed in the ```pdf-operations.js``` files, then pass the required library objects into the operation function as a parameter.
2. Now that we have the function code, we need to tell the other modules that it exists. Edit the [server operations](/server-node/src/pdf-operations.js) and the [client operations](/client-ionic/src/utils/pdf-operations.ts) files to add your new operation! (Try to follow existing patterns where possible, keep the added operations in alphabetical order in the files).
3. If you added a wrapper function to the [client operations](/client-ionic/src/utils/pdf-operations.ts) file, you will also need to add the TypeScript declarations to the [declaration](/client-ionic/declarations/shared-operations.d.ts) file. See the other module declarations for examples.
### Adding a server only operation
> WIP

View File

@ -160,9 +160,7 @@ A: Available in the internal API, S: Available on the node server, C: Available
For initial instructions look at [CONTRIBUTE.md](./CONTRIBUTE.md)
/*
<!--
///// CONVERT 2 pdf
file2pdf
url2pdf
@ -220,4 +218,5 @@ detect/split scanned
add image
add watermark
sign
*/
*/
-->

View File

@ -8,7 +8,10 @@
"shared-operations"
],
"scripts": {
"dev": "concurrently --names \"node,ionic\" -c \"red.bold,cyan.bold\" --kill-others \"npm run -w server-node dev\" \"npm run -w client-ionic dev\""
"dev-all": "concurrently --names \"node,ionic\" -c \"red.bold,cyan.bold\" --kill-others \"npm run -w server-node dev\" \"npm run -w client-ionic dev\"",
"update-all-dependencies": "npm i --workspace=server-node --workspace=client-tauri --workspace=shared-operation",
"update-backend-dependencies": "npm i --workspace=server-node --workspace=shared-operation",
"update-frontend-dependencies": "npm i --workspace=client-tauri --workspace=shared-operation"
},
"devDependencies": {
"concurrently": "^8.2.2"

View File

@ -1,3 +0,0 @@
declare module '#pdfcpu' {
export function oneToOne(wasmArray: string[], snapshot: Uint8Array): Promise<Uint8Array>;
}

View File

@ -1,85 +0,0 @@
import Joi from 'joi';
import { JoiPdfFileSchema } from '../wrappers/PdfFile';
export class RecordConstraint {
record: Record<string, FieldConstraint>;
constructor(record: Record<string, FieldConstraint>) {
this.record = record;
}
toJoiSchema() {
const newSchemaObj: any = {};
Object.keys(this.record).forEach(key => {
newSchemaObj[key] = this.record[key].toJoiSchema();
});
return Joi.object(newSchemaObj);
}
};
export class FieldConstraint {
displayNameKey: string;
type: "file.pdf" | "files.pdf" | "string" | "number" | number[] | string[] | RecordConstraint;
required: boolean;
hintKey?: string;
customSchema?: Joi.Schema;
constructor(displayNameKey: string,
type: "file.pdf" | "files.pdf" | "string" | "number" | number[] | string[] | RecordConstraint,
required: boolean,
hintKey?: string,
customSchema?: Joi.Schema) {
this.displayNameKey = displayNameKey;
this.type = type;
this.required = required;
this.hintKey = hintKey;
this.customSchema = customSchema;
}
toJoiSchema(): Joi.Schema {
if (this.customSchema) return this.customSchema;
var schema: Joi.Schema;
if (Array.isArray(this.type)) {
if (this.type.every(e => typeof e == 'string')) {
schema = Joi.string().valid(...this.type);
} else if (this.type.every(e => typeof e == 'number')) {
schema = Joi.number().valid(...this.type);
} else {
schema = Joi.any().valid(this.type);
}
} else if (typeof this.type == 'string') {
switch (this.type) {
case "file.pdf":
schema = JoiPdfFileSchema;
break;
case "files.pdf":
schema = Joi.array().items(JoiPdfFileSchema);
break;
case "string":
schema = Joi.string();
break;
case "number":
schema = Joi.number();
break;
default:
throw new Error(`UiConf type '${this.type}' not supported`)
}
} else if (this.type instanceof RecordConstraint) {
schema = this.type.toJoiSchema()
} else {
throw new Error(`UiConf type '${this.type}' not supported`)
}
if (this.required) {
schema = schema.required();
}
return schema;
}
}

View File

@ -1,6 +1,5 @@
import { PdfFile, RepresentationType } from "../wrappers/PdfFile";
import { FieldConstraint, RecordConstraint } from '../dynamic-ui/OperatorConstraints'
import { Operator, Progress, oneToOne } from ".";
import * as pdfcpuWrapper from "#pdfcpu"; // This is updated by tsconfig.json/paths for the context (browser, node, etc.) this module is used in.